Заявките не са строго еквивалентни
За да направите контекста ясен:
max(id)
изключваNULL
стойности. НоORDER BY ... LIMIT 1
не.NULL
стойностите се сортират последни във възходящ ред и първи в низходящ. Така чеIndex Scan Backward
може да не намери най-голямата стойност (споредmax()
) първи, но произволен брой отNULL
стойности.
Формалният еквивалент на:
SELECT max(id) FROM testview;
не е:
SELECT id FROM testview ORDER BY id DESC LIMIT 1;
но:
SELECT id FROM testview ORDER BY id DESC NULLS LAST LIMIT 1;
Последната заявка не получава плана за бърза заявка. Но би било с индекс със съвпадащ ред на сортиране:(id DESC NULLS LAST)
.
Това е различно за агрегатните функции min()
и max()
. Те получават бърз план при насочване към таблица test1
директно използвайки обикновения PK индекс на (id)
. Но не и когато се базира на изгледа (или директно на основната заявка за присъединяване - изгледът не е блокерът). Индекс, сортиращ NULL стойности на правилното място, едва ли има някакъв ефект.
Ние познайте този id
в тази заявка никога не може да бъде NULL
. Колоната е дефинирана NOT NULL
. И обединяването в изгледа на практика е INNER JOIN
което не може да въведе NULL
стойности за id
.
Ние също знайте, че индексът на test.id
не може да съдържа NULL стойности.
Но програмата за планиране на заявки на Postgres не е AI. (Нито се опитва да бъде, това може бързо да излезе извън ръцете.) Виждам два недостатъка :
min()
иmax()
вземете бързия план само при насочване към таблицата, независимо от реда на сортиране на индекса, се добавя условие за индекс:Index Cond: (id IS NOT NULL)
ORDER BY ... LIMIT 1
получава бързия план само с точно съвпадащ ред на сортиране на индекса.
Не съм сигурен дали това може да се подобри (лесно).
db<>fiddle тук - демонстриране на всичко по-горе
Индекси
Този индекс е напълно безполезен:
CREATE INDEX ON "test" ("id");
PK на test.id
е внедрен с уникален индекс в колоната, който вече покрива всичко, което допълнителният индекс може да направи за вас.
Може да има още, чакаме въпросът да се изясни.
Изкривен тестов случай
Тестовият случай е твърде далеч от действителния случай на употреба, за да има смисъл.
При тестовата настройка всяка таблица има 100k реда, няма гаранция, че всяка стойност в joincol
има съвпадение от другата страна и двете колони могат да бъдат NULL
Вашият реален случай има 10 милиона реда в table1
и <100 реда в table2
, всяка стойност в table1.joincol
има съвпадение в table2.joincol
, и двете са дефинирани NOT NULL
и table2.joincol
е уникален. Класическа връзка "един към много". Трябва да има UNIQUE
ограничение на table2.joincol
и FK ограничение t1.joincol --> t2.joincol
.
Но в момента всичко това е изкривено във въпроса. Очакваме, докато това бъде почистено.