Za předpokladu relativně málo řádků v options
pro mnoho řádků v records
.
Obvykle byste měli vyhledávací tabulku options
na který se odkazuje z records.option_id
, ideálně s omezením cizího klíče. Pokud tak neučiníte, navrhuji vytvořit jeden pro vynucení referenční integrity:
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;
Pak již není potřeba emulovat volné prohledávání indexů a toto se stává velmi jednoduchým a rychlým . Korelované poddotazy mohou používat prostý index na (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;
To zahrnuje možnosti, které v tabulce records
neodpovídají . Pro max_id
získáte hodnotu NULL a takové řádky můžete snadno odstranit ve vnějším SELECT
v případě potřeby.
Nebo (stejný výsledek):
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;
Může být o něco rychlejší. Poddotaz používá pořadí řazení DESC NULLS LAST
- stejné jako agregační funkce max()
který ignoruje hodnoty NULL. Řazení pouze DESC
bude mít nejprve NULL:
- Proč jsou hodnoty NULL na prvním místě při objednávání DESC v dotazu PostgreSQL?
Perfektní index pro toto:
CREATE INDEX on records (option_id, id DESC NULLS LAST);
Na pořadí řazení indexu příliš nezáleží, pokud jsou sloupce definovány NOT NULL
.
Stále může být sekvenční skenování na malém stole options
, to je jen nejrychlejší způsob, jak načíst všechny řádky. ORDER BY
může přinést (pouze) skenování indexu pro načtení předem seřazených řádků.
Velká tabulka records
je přístupný pouze prostřednictvím (bitmapového) indexového skenování nebo, je-li to možné, pouze indexového skenování .
db<>zde hrajte - zobrazující dvě skenování pouze s indexem pro jednoduchý případ
Starý sqlfiddle
Nebo použijte LATERAL
se připojí pro podobný efekt v Postgres 9.3+:
- Optimalizujte dotaz GROUP BY pro načtení posledního řádku na uživatele