Frågor inte strikt likvärdiga
För att göra sammanhanget tydligt:
max(id)
exkluderarNULL
värden. MenORDER BY ... LIMIT 1
inte.NULL
värden sorteras sist i stigande sorteringsordning och först i fallande. Alltså enIndex Scan Backward
kanske inte hittar det största värdet (enligtmax()
) först, men valfritt antalNULL
värden.
Den formella motsvarigheten till:
SELECT max(id) FROM testview;
är inte:
SELECT id FROM testview ORDER BY id DESC LIMIT 1;
men:
SELECT id FROM testview ORDER BY id DESC NULLS LAST LIMIT 1;
Den senare frågan får inte den snabba frågeplanen. Men det skulle med ett index med matchande sorteringsordning:(id DESC NULLS LAST)
.
Det är annorlunda för de aggregerade funktionerna min()
och max()
. De får en snabb plan när de riktar in sig på tabellen test1
direkt med det vanliga PK-indexet på (id)
. Men inte när den baseras på vyn (eller den underliggande join-frågan direkt - vyn är inte blockeraren). Ett index som sorterar NULL-värden på rätt plats har knappast någon effekt.
Vi vet att id
i den här frågan kan aldrig vara NULL
. Kolumnen är definierad NOT NULL
. Och sammanfogningen i vyn är faktiskt en INNER JOIN
som inte kan introducera NULL
värden för id
.
Vi vet också att indexet på test.id
kan inte innehålla NULL-värden.
Men Postgres frågeplanerare är inte en AI. (Det försöker det heller inte vara, det kan snabbt gå ur händerna.) Jag ser två brister :
min()
ochmax()
få den snabba planen endast när du riktar in tabellen, oavsett indexsorteringsordning, läggs ett indexvillkor till:Index Cond: (id IS NOT NULL)
ORDER BY ... LIMIT 1
får den snabba planen endast med exakt matchande indexsorteringsordning.
Inte säker på om det kan förbättras (lätt).
db<>fiol här - demonstrera allt ovan
Index
Detta index är helt värdelöst:
CREATE INDEX ON "test" ("id");
PK på test.id
implementeras med ett unikt index på kolumnen, som redan täcker allt det extra indexet kan göra för dig.
Det kan finnas fler som väntar på att frågan ska klarna upp.
Förvrängt testfall
Testfallet är för långt bort från det faktiska användningsfallet för att vara meningsfullt.
I testinställningen har varje tabell 100 000 rader, det finns ingen garanti för att varje värde i joincol
har en matchning på andra sidan, och båda kolumnerna kan vara NULL
Ditt riktiga fall har 10 miljoner rader i table1
och <100 rader i table2
, varje värde i table1.joincol
har en matchning i table2.joincol
, båda är definierade NOT NULL
och table2.joincol
är unik. En klassisk en-till-många-relation. Det bör finnas en UNIQUE
begränsning på table2.joincol
och en FK-begränsning t1.joincol --> t2.joincol
.
Men det är just nu allt vridet i frågan. Stanna tills det är städat.