Dengan asumsi relatif sedikit baris dalam options
untuk banyak baris dalam records
.
Biasanya, Anda akan melihat tabel options
yang dirujuk dari records.option_id
, idealnya dengan batasan kunci asing. Jika tidak, saya sarankan untuk membuatnya untuk menegakkan integritas referensial:
CREATE TABLE options (
option_id int PRIMARY KEY
, option text UNIQUE NOT NULL
);
INSERT INTO options
SELECT DISTINCT option_id, 'option' || option_id -- dummy option names
FROM records;
Maka tidak perlu lagi meniru pemindaian indeks longgar dan ini menjadi sangat sederhana dan cepat . Subkueri terkait dapat menggunakan indeks biasa pada (option_id, id)
.
SELECT option_id, (SELECT max(id)
FROM records
WHERE option_id = o.option_id) AS max_id
FROM options o
ORDER BY 1;
Ini termasuk opsi tanpa kecocokan di tabel records
. Anda mendapatkan NULL untuk max_id
dan Anda dapat dengan mudah menghapus baris seperti itu di SELECT
outer luar jika diperlukan.
Atau (hasil yang sama):
SELECT option_id, (SELECT id
FROM records
WHERE option_id = o.option_id
ORDER BY id DESC NULLS LAST
LIMIT 1) AS max_id
FROM options o
ORDER BY 1;
Mungkin sedikit lebih cepat. Subquery menggunakan urutan pengurutan DESC NULLS LAST
- sama dengan fungsi agregat max()
yang mengabaikan nilai NULL. Hanya menyortir DESC
akan memiliki NULL terlebih dahulu:
- Mengapa nilai NULL didahulukan saat memesan DESC dalam kueri PostgreSQL?
Indeks sempurna untuk ini:
CREATE INDEX on records (option_id, id DESC NULLS LAST);
Urutan pengurutan indeks tidak terlalu menjadi masalah saat kolom ditentukan NOT NULL
.
Masih ada pemindaian berurutan di tabel kecil options
, itu hanya cara tercepat untuk mengambil semua baris. ORDER BY
dapat membawa pemindaian indeks (hanya) untuk mengambil baris yang telah diurutkan sebelumnya.
Tabel besar records
hanya diakses melalui pemindaian indeks (bitmap) atau, jika memungkinkan, pemindaian hanya indeks .
db<>main biola di sini - menampilkan dua pemindaian indeks saja untuk kasus sederhana
sqlfiddle lama
Atau gunakan LATERAL
bergabung untuk efek serupa di Postgres 9.3+:
- Optimalkan kueri GROUP BY untuk mengambil baris terbaru per pengguna