Pembaruan: Menguji semua 5 kueri dalam SQLfiddle dengan 100K baris (dan 2 kasus terpisah, satu dengan beberapa (25) nilai berbeda dan lainnya dengan banyak (sekitar nilai 25K).
Permintaan yang sangat sederhana adalah menggunakan UNION DISTINCT
. Saya pikir akan lebih efisien jika ada indeks terpisah pada masing-masing dari empat kolom. Ini akan efisien dengan indeks terpisah pada masing-masing dari empat kolom, jika Postgres telah menerapkan optimisasi pemindaian indeks longgar , yang belum. Jadi kueri ini tidak akan efisien karena membutuhkan 4 pemindaian tabel (dan tidak ada indeks yang digunakan):
-- 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 ;
Lain akan menjadi pertama UNION ALL
dan kemudian digunakan DISTINCT
. Ini juga akan membutuhkan 4 scan tabel (dan tidak menggunakan indeks). Bukan efisiensi yang buruk ketika nilainya sedikit, dan dengan lebih banyak nilai menjadi yang tercepat dalam pengujian (tidak luas) saya:
-- 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 ;
Jawaban lain telah memberikan lebih banyak opsi menggunakan fungsi array atau LATERAL
sintaks. Permintaan Jack ( 187 ms, 261 ms
) memiliki kinerja yang masuk akal tetapi permintaan AndriyM tampaknya lebih efisien ( 125 ms, 155 ms
). Keduanya melakukan satu pemindaian berurutan dari tabel dan tidak menggunakan indeks apa pun.
Sebenarnya hasil permintaan Jack sedikit lebih baik daripada yang ditunjukkan di atas (jika kita menghapus order by
) dan dapat lebih ditingkatkan dengan menghapus 4 internal distinct
dan hanya menyisakan yang eksternal.
Akhirnya, jika - dan hanya jika - nilai yang berbeda dari 4 kolom relatif sedikit, Anda dapat menggunakan WITH RECURSIVE
retas / optimisasi yang dijelaskan di halaman Pemindaian Indeks Lepas di atas dan menggunakan semua 4 indeks, dengan hasil yang sangat cepat! Diuji dengan baris 100K yang sama dan sekitar 25 nilai berbeda yang tersebar di 4 kolom (berjalan hanya dalam 2 ms!) Sedangkan dengan nilai berbeda 25K itu paling lambat dengan 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
Untuk meringkas, ketika nilai-nilai yang berbeda sedikit, kueri rekursif adalah pemenang mutlak sementara dengan banyak nilai, nilai ke-2 saya, Jack (versi yang ditingkatkan di bawah) dan kueri AndriyM adalah yang berkinerja terbaik.
Penambahan yang terlambat, variasi pada kueri ke-1 yang meskipun memiliki operasi yang sangat berbeda, berkinerja jauh lebih baik daripada yang pertama dan hanya sedikit lebih buruk daripada yang ke-2:
-- 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 ;
dan Jack membaik:
-- 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 ;
?