Aggiornamento: testate tutte e 5 le query in SQLfiddle con 100K righe (e 2 casi separati, uno con pochi (25) valori distinti e un altro con lotti (circa 25K valori).
Una query molto semplice sarebbe da usare UNION DISTINCT
. Penso che sarebbe più efficiente se ci fosse un indice separato su ciascuna delle quattro colonne. Sarebbe efficiente con un indice separato su ciascuna delle quattro colonne, se Postgres avesse implementato l' ottimizzazione di Scansione indice libera , cosa che non ha fatto. Quindi questa query non sarà efficiente in quanto richiede 4 scansioni della tabella (e non viene utilizzato alcun indice):
-- Query 1. (334 ms, 368ms)
SELECT a AS abcd FROM tablename
UNION -- means UNION DISTINCT
SELECT b FROM tablename
UNION
SELECT c FROM tablename
UNION
SELECT d FROM tablename ;
Un altro sarebbe prima di tutto UNION ALL
e poi usarlo DISTINCT
. Ciò richiederà anche 4 scansioni di tabelle (e nessun uso di indici). Non cattiva efficienza quando i valori sono pochi e con più valori diventa il più veloce nel mio test (non esteso):
-- Query 2. (87 ms, 117 ms)
SELECT DISTINCT a AS abcd
FROM
( SELECT a FROM tablename
UNION ALL
SELECT b FROM tablename
UNION ALL
SELECT c FROM tablename
UNION ALL
SELECT d FROM tablename
) AS x ;
Le altre risposte hanno fornito più opzioni usando le funzioni dell'array o la LATERAL
sintassi. La query di Jack ( 187 ms, 261 ms
) ha prestazioni ragionevoli ma la query di AndriyM sembra più efficiente ( 125 ms, 155 ms
). Entrambi eseguono una scansione sequenziale della tabella e non utilizzano alcun indice.
In realtà i risultati della query di Jack sono leggermente migliori di quelli mostrati sopra (se rimuoviamo il order by
) e possono essere ulteriormente migliorati rimuovendo i 4 interni distinct
e lasciando solo quello esterno.
Infine, se - e solo se - i valori distinti delle 4 colonne sono relativamente pochi, puoi usare l' WITH RECURSIVE
hack / l'ottimizzazione descritta nella pagina Scansione indice sciolta sopra e usare tutti e 4 gli indici, con un risultato notevolmente veloce! Testato con le stesse righe da 100 K e circa 25 valori distinti distribuiti su 4 colonne (funziona in soli 2 ms!) Mentre con 25 K valori distinti è il più lento con 368 ms:
-- Query 3. (2 ms, 368ms)
WITH RECURSIVE
da AS (
SELECT min(a) AS n FROM observations
UNION ALL
SELECT (SELECT min(a) FROM observations
WHERE a > s.n)
FROM da AS s WHERE s.n IS NOT NULL ),
db AS (
SELECT min(b) AS n FROM observations
UNION ALL
SELECT (SELECT min(b) FROM observations
WHERE b > s.n)
FROM db AS s WHERE s.n IS NOT NULL ),
dc AS (
SELECT min(c) AS n FROM observations
UNION ALL
SELECT (SELECT min(c) FROM observations
WHERE c > s.n)
FROM dc AS s WHERE s.n IS NOT NULL ),
dd AS (
SELECT min(d) AS n FROM observations
UNION ALL
SELECT (SELECT min(d) FROM observations
WHERE d > s.n)
FROM db AS s WHERE s.n IS NOT NULL )
SELECT n
FROM
( TABLE da UNION
TABLE db UNION
TABLE dc UNION
TABLE dd
) AS x
WHERE n IS NOT NULL ;
SQLfiddle
Per riassumere, quando i valori distinti sono pochi, la query ricorsiva è la vincitrice assoluta mentre con molti valori, la mia seconda, le query di Jack (versione migliorata di seguito) e AndriyM sono le migliori.
Aggiunte tardive, una variazione sulla prima query che, nonostante le operazioni extra distinte, offre prestazioni molto migliori rispetto alla prima originale e solo leggermente peggiori della seconda:
-- Query 1b. (85 ms, 149 ms)
SELECT DISTINCT a AS n FROM observations
UNION
SELECT DISTINCT b FROM observations
UNION
SELECT DISTINCT c FROM observations
UNION
SELECT DISTINCT d FROM observations ;
e Jack è migliorato:
-- Query 4b. (104 ms, 128 ms)
select distinct unnest( array_agg(a)||
array_agg(b)||
array_agg(c)||
array_agg(d) )
from t ;
SELECT a FROM tablename UNION SELECT b FROM tablename UNION SELECT c FROM tablename UNION SELECT d FROM tablename ;
?