Supponendo relativamente pochi righe in options
per molte righe in records
.
In genere, dovresti cercare una tabella options
a cui fa riferimento records.option_id
, idealmente con un vincolo di chiave esterna. In caso contrario, suggerisco di crearne uno per rafforzare l'integrità referenziale:
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;
Quindi non c'è più bisogno di emulare una scansione dell'indice sciolto e questo diventa molto semplice e veloce . Le sottoquery correlate possono utilizzare un semplice indice su (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;
Ciò include le opzioni senza corrispondenza nella tabella records
. Ottieni NULL per max_id
e puoi facilmente rimuovere tali righe in un SELECT
esterno se necessario.
Oppure (stesso risultato):
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;
Potrebbe essere leggermente più veloce. La sottoquery utilizza l'ordinamento DESC NULLS LAST
- come la funzione aggregata max()
che ignora i valori NULL. Ordinando solo DESC
prima avrebbe NULL:
- Perché i valori NULL vengono prima quando si ordina DESC in una query PostgreSQL?
L'indice perfetto per questo:
CREATE INDEX on records (option_id, id DESC NULLS LAST);
L'ordinamento degli indici non ha molta importanza mentre le colonne sono definite NOT NULL
.
Potrebbe esserci ancora una scansione sequenziale sulla piccola tabella options
, questo è solo il modo più veloce per recuperare tutte le righe. Il ORDER BY
può portare a una scansione (solo) dell'indice per recuperare le righe preordinate.
La tabella grande records
è accessibile solo tramite scansione dell'indice (bitmap) o, se possibile, scansione solo indice .
db<>gioca qui - mostra due scansioni solo indice per il caso semplice
Old sqlfiddle
Oppure usa LATERAL
si unisce per un effetto simile in Postgres 9.3+:
- Ottimizza la query GROUP BY per recuperare l'ultima riga per utente