Requêtes non strictement équivalentes
Pour clarifier le contexte :
max(id)
exclutNULL
valeurs. MaisORDER BY ... LIMIT 1
pas.NULL
les valeurs sont triées en dernier dans l'ordre croissant et en premier dans l'ordre décroissant. Donc unIndex Scan Backward
peut ne pas trouver la plus grande valeur (selonmax()
) d'abord, mais n'importe quel nombre deNULL
valeurs.
L'équivalent formel de :
SELECT max(id) FROM testview;
n'est pas :
SELECT id FROM testview ORDER BY id DESC LIMIT 1;
mais :
SELECT id FROM testview ORDER BY id DESC NULLS LAST LIMIT 1;
Cette dernière requête n'obtient pas le plan de requête rapide. Mais ce serait le cas avec un index avec un ordre de tri correspondant :(id DESC NULLS LAST)
.
C'est différent pour les fonctions d'agrégation min()
et max()
. Ceux-ci obtiennent un plan rapide lors du ciblage de la table test1
directement en utilisant l'index PK simple sur (id)
. Mais pas lorsqu'il est basé sur la vue (ou directement sur la requête de jointure sous-jacente - la vue n'est pas le bloqueur). Un index triant les valeurs NULL au bon endroit n'a pratiquement aucun effet.
Nous sachez que id
dans cette requête ne peut jamais être NULL
. La colonne est définie NOT NULL
. Et la jointure dans la vue est effectivement une INNER JOIN
qui ne peut pas introduire NULL
valeurs pour id
.
Nous sachez aussi que l'index sur test.id
ne peut pas contenir de valeurs NULL.
Mais le planificateur de requêtes Postgres n'est pas une IA. (Il n'essaie pas non plus de l'être, cela pourrait rapidement devenir incontrôlable.) Je vois deux lacunes :
min()
etmax()
obtenir le plan rapide uniquement lors du ciblage de la table, quel que soit l'ordre de tri de l'index, une condition d'index est ajoutée :Index Cond: (id IS NOT NULL)
ORDER BY ... LIMIT 1
obtient le plan rapide uniquement avec l'ordre de tri de l'index correspondant exactement.
Je ne sais pas si cela pourrait être amélioré (facilement).
db<>violon ici - démontrant tout ce qui précède
Index
Cet index est complètement inutile :
CREATE INDEX ON "test" ("id");
Le PK sur test.id
est implémenté avec un index unique sur la colonne, qui couvre déjà tout ce que l'index supplémentaire pourrait faire pour vous.
Il peut y en avoir d'autres, en attendant que la question soit éclaircie.
Cas de test déformé
Le cas de test est trop éloigné du cas d'utilisation réel pour être significatif.
Dans la configuration de test, chaque table a 100k lignes, il n'y a aucune garantie que chaque valeur dans joincol
a une correspondance de l'autre côté, et les deux colonnes peuvent être NULL
Votre cas réel a 10 millions de lignes dans table1
et <100 lignes dans table2
, chaque valeur dans table1.joincol
a une correspondance dans table2.joincol
, les deux sont définis NOT NULL
, et table2.joincol
est unique. Une relation un-à-plusieurs classique. Il devrait y avoir un UNIQUE
contrainte sur table2.joincol
et une contrainte FK t1.joincol --> t2.joincol
.
Mais c'est actuellement tout tordu dans la question. Attendre jusqu'à ce que ce soit nettoyé.