Förutsatt att det är relativt få rader i options
för många rader i records
.
Vanligtvis skulle du ha en uppslagstabell options
som refereras från records.option_id
, helst med en främmande nyckel-begränsning. Om du inte gör det, föreslår jag att du skapar en för att upprätthålla referensintegritet:
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;
Då finns det ingen anledning att emulera en lös indexskanning längre och detta blir mycket enkelt och snabbt . Korrelerade underfrågor kan använda ett vanligt index på (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;
Detta inkluderar alternativ utan matchning i tabellen records
. Du får NULL för max_id
och du kan enkelt ta bort sådana rader i en yttre SELECT
om det behövs.
Eller (samma resultat):
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;
Kan vara något snabbare. Underfrågan använder sorteringsordningen DESC NULLS LAST
- samma som aggregatfunktionen max()
som ignorerar NULL-värden. Sorterar bara DESC
skulle ha NULL först:
- Varför kommer NULL-värden först när man beställer DESC i en PostgreSQL-fråga?
Det perfekta indexet för detta:
CREATE INDEX on records (option_id, id DESC NULLS LAST);
Indexsorteringsordningen spelar inte så stor roll när kolumner är definierade NOT NULL
.
Det kan fortfarande göras en sekventiell genomsökning av den lilla tabellen options
, det är bara det snabbaste sättet att hämta alla rader. ORDER BY
kan ta in en (endast) indexskanning för att hämta försorterade rader.
Den stora tabellen records
nås endast via (bitmapps) indexskanning eller, om möjligt, endast indexskanning .
db<>spela här - visar två indexsökningar för det enkla fallet
Old sqlfiddle
Eller använd LATERAL
går med för en liknande effekt i Postgres 9.3+:
- Optimera GROUP BY-frågan för att hämta den senaste raden per användare