Dotazy nejsou přesně ekvivalentní
Aby byl kontext jasný:
max(id)
nezahrnujeNULL
hodnoty. AleORDER BY ... LIMIT 1
ne.NULL
hodnoty seřadit jako poslední ve vzestupném pořadí a jako první sestupně. TakžeIndex Scan Backward
nemusí najít největší hodnotu (podlemax()
) první, ale libovolný početNULL
hodnoty.
Formální ekvivalent:
SELECT max(id) FROM testview;
není:
SELECT id FROM testview ORDER BY id DESC LIMIT 1;
ale:
SELECT id FROM testview ORDER BY id DESC NULLS LAST LIMIT 1;
Druhý dotaz nezíská plán rychlých dotazů. Ale bylo by to s indexem s odpovídajícím pořadím řazení:(id DESC NULLS LAST)
.
To se liší pro agregační funkce min()
a max()
. Ti získají rychlý plán při cílení na tabulku test1
přímo pomocí prostého indexu PK na (id)
. Ale ne na základě pohledu (nebo přímo základního spojovacího dotazu - pohled není blokátorem). Index setřídění hodnot NULL na správném místě nemá téměř žádný účinek.
My vědět, že id
v tomto dotazu nikdy nemůže být NULL
. Sloupec je definován NOT NULL
. A spojení v pohledu je ve skutečnosti INNER JOIN
který nemůže zavést NULL
hodnoty pro id
.
My také vědět, že index na test.id
nemůže obsahovat hodnoty NULL.
Ale plánovač dotazů Postgres není AI. (Ani se o to nesnaží, to by se mohlo rychle vymknout z rukou.) Vidím dva nedostatky :
min()
amax()
získat rychlý plán pouze při cílení na tabulku, bez ohledu na pořadí řazení indexu, je přidána podmínka indexu:Index Cond: (id IS NOT NULL)
ORDER BY ... LIMIT 1
získá rychlý plán pouze s přesně odpovídajícím pořadím řazení indexu.
Nejste si jisti, zda by se to dalo (snadno) zlepšit.
db<>fiddle zde - předvedení všeho výše uvedeného
Indexy
Tento index je úplně k ničemu:
CREATE INDEX ON "test" ("id");
PK na test.id
je implementován s jedinečným indexem ve sloupci, který již pokrývá vše, co by pro vás mohl dodatečný index udělat.
Může jich být více, čeká se, až se otázka vyjasní.
Zkreslený testovací případ
Testovací případ je příliš daleko od skutečného případu použití, než aby měl smysl.
V nastavení testu má každá tabulka 100 000 řádků, není zaručeno, že každá hodnota v joincol
má shodu na druhé straně a oba sloupce mohou mít hodnotu NULL
Váš skutečný případ má 10 milionů řádků v table1
a <100 řádků v table2
, každá hodnota v table1.joincol
má shodu v table2.joincol
, oba jsou definovány NOT NULL
a table2.joincol
je jedinečný. Klasický vztah jeden k mnoha. Mělo by existovat UNIQUE
omezení na table2.joincol
a omezení FK t1.joincol --> t2.joincol
.
Ale to je v současné době v otázce vše zkroucené. Čekáme, dokud to nebude vyčištěno.