Ervan uitgaande dat relatief weinig rijen in options
voor veel rijen in records
.
Normaal gesproken zou u een tabel options
. opzoeken waarnaar wordt verwezen vanuit records.option_id
, idealiter met een externe sleutelbeperking. Als je dat niet doet, raad ik aan er een te maken om referentiële integriteit af te dwingen:
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;
Dan is het niet meer nodig om een losse indexscan te emuleren en dit wordt heel eenvoudig en snel . Gecorreleerde subquery's kunnen een gewone index gebruiken op (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;
Dit omvat opties zonder overeenkomst in tabel records
. Je krijgt NULL voor max_id
en je kunt zulke rijen gemakkelijk verwijderen in een buitenste SELECT
indien nodig.
Of (zelfde resultaat):
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;
Mag iets sneller. De subquery gebruikt de sorteervolgorde DESC NULLS LAST
- hetzelfde als de verzamelfunctie max()
die NULL-waarden negeert. Alleen DESC
sorteren zou eerst NULL hebben:
- Waarom komen NULL-waarden eerst bij het bestellen van DESC in een PostgreSQL-query?
De perfecte index hiervoor:
CREATE INDEX on records (option_id, id DESC NULLS LAST);
Index-sorteervolgorde maakt niet veel uit, terwijl kolommen zijn gedefinieerd NOT NULL
.
Er kan nog steeds een sequentiële scan zijn op de kleine tafel options
, dat is gewoon de snelste manier om alle rijen op te halen. De ORDER BY
kan een (alleen) indexscan opleveren om voorgesorteerde rijen op te halen.
De grote tabel records
is alleen toegankelijk via (bitmap) indexscan of, indien mogelijk, index-only scan .
db<>viool hier - toont twee alleen-index scans voor het eenvoudige geval
Oude sqlfiddle
Of gebruik LATERAL
sluit zich aan voor een soortgelijk effect in Postgres 9.3+:
- Optimaliseer de GROUP BY-query om de laatste rij per gebruiker op te halen