Forespørgsler er ikke strengt ækvivalente
For at gøre konteksten klar:
max(id)
udelukkerNULL
værdier. MenORDER BY ... LIMIT 1
ikke.NULL
værdier sorteres sidst i stigende sorteringsrækkefølge og først i faldende. Altså enIndex Scan Backward
finder muligvis ikke den største værdi (ifølgemax()
) først, men et vilkårligt antalNULL
værdier.
Den formelle ækvivalent til:
SELECT max(id) FROM testview;
er ikke:
SELECT id FROM testview ORDER BY id DESC LIMIT 1;
men:
SELECT id FROM testview ORDER BY id DESC NULLS LAST LIMIT 1;
Sidstnævnte forespørgsel får ikke den hurtige forespørgselsplan. Men det ville med et indeks med matchende sorteringsrækkefølge:(id DESC NULLS LAST)
.
Det er anderledes for de samlede funktioner min()
og max()
. De får en hurtig plan, når de målretter tabel test1
direkte ved at bruge det almindelige PK-indeks på (id)
. Men ikke når det er baseret på visningen (eller den underliggende join-forespørgsel direkte - visningen er ikke blokeringen). Et indeks, der sorterer NULL-værdier på det rigtige sted, har næppe nogen effekt.
Vi ved det id
i denne forespørgsel kan aldrig være NULL
. Kolonnen er defineret NOT NULL
. Og joinforbindelsen i visningen er reelt en INNER JOIN
som ikke kan introducere NULL
værdier for id
.
Vi ved også, at indekset på test.id
kan ikke indeholde NULL-værdier.
Men Postgres-forespørgselsplanlæggeren er ikke en AI. (Det forsøger det heller ikke at være, det kan hurtigt komme ud af hænderne.) Jeg ser to mangler :
min()
ogmax()
få den hurtige plan kun, når du målretter tabellen, uanset indekssorteringsrækkefølgen tilføjes en indeksbetingelse:Index Cond: (id IS NOT NULL)
ORDER BY ... LIMIT 1
får kun den hurtige plan med den nøjagtigt matchende indekssorteringsrækkefølge.
Ikke sikker på, om det kan forbedres (let).
db<>fiddle her - demonstrerer alt ovenstående
Indekser
Dette indeks er fuldstændig ubrugeligt:
CREATE INDEX ON "test" ("id");
PK'en på test.id
er implementeret med et unikt indeks på kolonnen, der allerede dækker alt, hvad det ekstra indeks kan gøre for dig.
Der kan være flere, der venter på, at spørgsmålet bliver klaret.
Forvrænget testcase
Testcasen er for langt væk fra den faktiske use case til at være meningsfuld.
I testopsætningen har hver tabel 100.000 rækker, der er ingen garanti for, at hver værdi i joincol
har et match på den anden side, og begge kolonner kan være NULL
Din rigtige sag har 10M rækker i table1
og <100 rækker i table2
, hver værdi i table1.joincol
har et match i table2.joincol
, begge er defineret NOT NULL
, og table2.joincol
er unik. Et klassisk en-til-mange forhold. Der skal være en UNIQUE
begrænsning på table2.joincol
og en FK-begrænsning t1.joincol --> t2.joincol
.
Men det er i øjeblikket alt fordrejet i spørgsmålet. Stående til der er ryddet op.