Risultati corretti?
Prima di tutto: correttezza. Vuoi produrre una serie di elementi unici? La tua query attuale non lo fa. La funzione uniq()
dal modulo intarray promette solo di:
rimuovere i duplicati adiacenti
Come indicato nel manuale , è necessario:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
Ti dà anche array ordinati - supponendo che lo desideri, non hai chiarito.
Vedo che hai sort()
nel violino , quindi questo potrebbe essere solo un refuso nella tua domanda.
Postgres 9.5
In entrambi i casi, sarà l'amore il nuovo Postgres 9.5 (attualmente in beta). Offre le funzionalità di array_agg_mult()
pronto all'uso e molto più veloce:
Ci sono stati anche altri miglioramenti delle prestazioni per la gestione dell'array.
domanda
Lo scopo principale di array_agg_mult()
è aggregare array multidimensionali, ma si producono comunque solo array monodimensionali. Quindi almeno proverei questa query alternativa:
SELECT l.d + r.d AS d_sum, array_agg(DISTINCT elem) AS result_arr
FROM left2 l
JOIN right2 r USING (t1)
, unnest(r.arr) elem
GROUP BY 1
ORDER BY 1;
Che affronta anche la tua domanda:
La funzione di aggregazione può rimuovere direttamente i duplicati?
Sì, può, con DISTINCT
. Ma questo non è più veloce rispetto uniq()
agli array di numeri interi, che è stato ottimizzato per gli array di numeri interi, mentre DISTINCT
è generico per tutti i tipi di dati qualificanti.
Non richiede il intarray
modulo. Tuttavia , il risultato non è necessariamente ordinato. Postgres utilizza algoritmi variabili per DISTINCT
(IIRC), i set di grandi dimensioni sono generalmente sottoposti a hash, quindi il risultato non viene ordinato a meno che non venga aggiunto esplicitamente ORDER BY
. Se sono necessari array ordinati, è possibile aggiungere ORDER BY
direttamente alla funzione aggregata:
array_agg(DISTINCT elem ORDER BY elem)
Ma in genere è più lento del fornire dati pre-ordinati a array_agg()
(un grande ordinamento rispetto a molti piccoli ordinamenti). Quindi vorrei ordinare in una sottoquery e quindi aggregare:
SELECT d_sum, uniq(array_agg(elem)) AS result_arr
FROM (
SELECT l.d + r.d AS d_sum, elem
FROM left2 l
JOIN right2 r USING (t1)
, unnest(r.arr) elem
ORDER BY 1, 2
) sub
GROUP BY 1
ORDER BY 1;
Questa è stata la variante più veloce nel mio test rapido su Postgres 9.4.
SQL Fiddle basato su quello che hai fornito.
Indice
Non vedo molto potenziale per nessun indice qui. L'unica opzione sarebbe:
CREATE INDEX ON right2 (t1, arr);
Ha senso solo se si ottengono scansioni solo indice da questo, cosa che succederà se la tabella sottostante right2
è sostanzialmente più ampia di queste sole due colonne e la propria configurazione si qualifica per scansioni solo indice. Dettagli nel Wiki di Postgres.
right2.arr
essere NULL come suggerisce lo schema demo? Hai bisogno di array ordinati come risultato?