sql >> Databáze >  >> RDS >> PostgreSQL

Výkonový vliv pohledu na agregovanou funkci vs. omezení sady výsledků

Dotazy nejsou přesně ekvivalentní

Aby byl kontext jasný:

  • max(id) nezahrnuje NULL hodnoty. Ale ORDER BY ... LIMIT 1 ne.
  • NULL hodnoty seřadit jako poslední ve vzestupném pořadí a jako první sestupně. Takže Index Scan Backward nemusí najít největší hodnotu (podle max() ) první, ale libovolný počet NULL 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() a max() 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.



  1. Heslo nekontroluje rozlišování malých a velkých písmen

  2. Pokus o získání skutečných dat, která způsobují výjimku

  3. drahokam mysql2 zkompilován pro špatnou klientskou knihovnu mysql

  4. Zkontrolovat, zda soubor existuje?