tl;dr Vous devez ajouter un index sur item_id
. La "magie noire" de l'indexation Postgres est couverte dans 11. Index
.
Vous avez un index composite sur (topic_id, item_id)
et l'ordre des colonnes est important. Postgres peut l'utiliser pour indexer les requêtes sur topic_id
, requêtes sur topic_id
et item_id
, mais pas (ou moins efficacement) item_id
seul.
De 11.3. Index multicolonnes ...
-- indexed
select *
from topics_items
where topic_id = ?
-- also indexed
select *
from topics_items
where topic_id = ?
and item_id = ?
-- probably not indexed
select *
from topics_items
where item_id = ?
En effet, un index composite tel que (topic_id, item_id)
stocke d'abord l'ID de sujet, puis un ID d'élément qui a également cet ID de sujet. Afin de rechercher efficacement un ID d'élément dans cet index, Postgres doit d'abord affiner la recherche avec un ID de sujet.
Postgres peut inverser un index s'il pense que cela en vaut la peine. S'il existe un petit nombre d'ID de sujet possibles et un grand nombre d'ID d'index possibles, il recherchera l'ID d'index dans chaque ID de sujet.
Par exemple, supposons que vous ayez 10 ID de sujet possibles et 1000 ID d'élément possibles et votre index (topic_id, index_id)
. C'est comme avoir 10 seaux d'ID de sujet clairement étiquetés, chacun contenant 1000 seaux d'ID d'élément clairement étiquetés à l'intérieur. Pour accéder aux compartiments d'ID d'élément, il doit regarder à l'intérieur de chaque compartiment d'ID de sujet. Pour utiliser cet index sur where item_id = 23
Postgres doit rechercher chacun des 10 compartiments d'ID de sujet pour tous les compartiments avec l'ID d'élément 23.
Mais si vous avez 1 000 ID de sujet possibles et 10 ID d'élément possibles, Postgres devra rechercher 1 000 compartiments d'ID de sujet. Il effectuera très probablement une analyse complète de la table à la place. Dans ce cas, vous voudriez inverser votre index et le rendre (item_id, topic_id)
.
Cela dépend fortement d'avoir de bonnes statistiques de table, ce qui signifie s'assurer que l'autovacuum fonctionne correctement.
Vous pouvez donc vous en tirer avec un seul index pour deux colonnes, si une colonne a beaucoup moins de variabilité qu'une autre.
Postgres peut également utiliser plusieurs index s'il pense que la requête sera exécutée plus vite
. Par exemple, si vous aviez un index sur topic_id
et un index sur item_id
, il peut utiliser les deux index et combiner les résultats. Par exemple where topic_id = 23 or item_id = 42
pouvez utiliser l'index topic_id pour rechercher l'ID de sujet 23 et l'index item_id pour rechercher l'ID d'élément 42, puis combiner les résultats.
C'est généralement plus lent que d'avoir un composé (topic_id, item_id)
indice. Cela peut également être plus lent que d'utiliser un seul index, alors ne soyez pas surpris si Postgres décide de ne pas utiliser plusieurs index.
En général, pour les index b-tree, lorsque vous avez deux colonnes, vous avez trois combinaisons possibles.
- a + b
- un
- b
Et vous avez besoin de deux index.
- (a, b) -- a et a + b
- (b) -- b
(a, b)
couvre à la fois les recherches pour a et a + b. (b)
couvre la recherche de b
.
Lorsque vous avez trois colonnes, vous avez sept combinaisons possibles.
- a + b + c
- a + b
- a + c
- un
- b + c
- b
- c
Mais vous n'avez besoin que de trois index.
- (a, b, c) -- a, a + b, a + b + c
- (b, c) -- b, b + c
- (c, a) -- c, c + a
Cependant, vous voulez probablement éviter d'avoir un index sur trois colonnes. C'est souvent plus lent . En fait, ce que vous voulez, c'est ceci.
- (a, b)
- (b, c)
- (c, une)
La lecture à partir d'un index est plus lente que la lecture à partir de la table. Vous voulez que vos index réduisent le nombre de lignes qui doivent être lues, mais vous ne voulez pas que Postgres ait à parcourir plus d'index que nécessaire.