Un index composite convient-il également aux requêtes sur le premier champ?

87

Disons que j'ai une table avec des champs Aet B. Je fais des requêtes régulières sur A+ B, alors j'ai créé un index composite sur (A,B). Les requêtes sur seulement Aseraient-elles également entièrement optimisées par l'index composite?

De plus, j'ai créé un index sur A, mais Postgres utilise toujours l'index composite pour les requêtes uniquement A. Si la réponse précédente est positive, je suppose que cela n’a pas vraiment d’importance, mais pourquoi sélectionne-t-il l’index composite par défaut, si l’ Aindice unique est disponible?

Luciano
la source
J'ai essayé de mettre en place un petit test pour cela. Dans mon cas, cependant, l'index à deux colonnes n'était utilisé que lorsque j'ai supprimé celui à une colonne, sans rapport avec celui qui avait été créé en premier. Il est intéressant de noter que si je créais d’abord l’index à deux colonnes, le plan initial utilisait une analyse de tas bitmap. Si j'ai créé l'index à une colonne, lancez la requête (analyse d'index utilisé) et supprimez l'index nouvellement créé. Le plan impliquant l'index à deux colonnes est passé en analyse d'index. Voir les étapes sur SQLFiddle
dezso
@ Dezso Intéressant. Où sont les coûts pour chaque requête?
Luciano
Coût d'analyse de l'index bitmap: 107,98, 43 ms de temps d'exécution. Analyse de l’index dans une colonne: coût 8,69, deux colonnes: 43,69. Les temps d'exécution ne diffèrent pas de manière significative (la fluctuation est supérieure à la différence entre les deux).
dezso
@ Luciano Pouvez-vous afficher le explain analyzeet le texte de la requête?
Craig Ringer

Réponses:

88

C'est certainement. Nous avons discuté de cela en détail sous cette question connexe:

L'espace est alloué en multiples de MAXALIGN, ce qui correspond généralement à 8 octets sur un système d'exploitation 64 bits ou (beaucoup moins commun) à 4 octets sur un système d'exploitation 32 bits. Si vous n'êtes pas sûr, vérifiez pg_controldata. Cela dépend également des types de données des colonnes indexées (certaines nécessitent un remplissage d'alignement) et du contenu réel.

Un index sur, par exemple, deux integercolonnes (4 octets chacune) finit généralement par être exactement aussi grand qu'un index sur une seule colonne, où 4 octets supplémentaires sont perdus pour le remplissage d'alignement.

Dans ce cas, le planificateur de requêtes n'a pas d'inconvénient à utiliser un index (a,b), comparé à un index (a). Et il est généralement préférable que plusieurs requêtes utilisent le même index. La chance pour qu'il (ou une partie de celui-ci) réside dans le cache (rapide) augmente quand il est partagé.

Si vous maintenez déjà un index activé (a,b), il n’a aucun sens de créer un autre index uniquement (a)- à moins qu’il soit nettement plus petit. La même chose est pas vrai pour les (b,a)contre (a). Suivez le lien à la première ligne pour en savoir plus.

En venant de la direction opposée, lorsque vous avez besoin d'un index supplémentaire comme celui-ci (a,b), envisagez de supprimer un index existant uniquement (a)- si possible. Souvent impossible car il s'agit de l'index d'une PK ou d'une UNIQUEcontrainte. Depuis Postgres 11, vous pouvez vous contenter d’ajouter bà la définition de la contrainte avec la INCLUDEclause. Détails dans le manuel.

Ou créez le nouvel index sur (b,a)pour couvrir les requêtes bsupplémentaires. Pour les seules conditions d'égalité, l'ordre des expressions d'index dans les index btree n'a pas d'importance. C'est le cas, cependant, lorsqu'il s'agit de conditions de distance. Voir:

L' inclusion de colonnes supplémentaires dans un index peut présenter des inconvénients , même si cet espace utilise uniquement de l'espace, sinon perdu par l'alignement de remplissage:

  • Chaque fois que la colonne supplémentaire est mise à jour, l'index a également besoin d'une mise à jour, ce qui peut entraîner des coûts supplémentaires pour les opérations d'écriture et créer davantage de blocages d'index.
  • HOT mises à jour (Tas uniquement Tuple) sur la table ne sont pas possibles en une colonne d'index est impliqué.

Plus sur les mises à jour HOT:

Comment mesurer la taille des objets:

Erwin Brandstetter
la source
1
Pourriez-vous étendre ceci pour dire que, si j'ai un index sur la colonne A et qu'il est nécessaire d'ajouter un index composé (A, B), l'index A devrait être supprimé? Si la réutilisation d'un index améliore l'efficacité du cache et que (A, B) optimise complètement A, alors il semble qu'un index supplémentaire sur A gaspillerait de l'espace et ralentirait potentiellement les choses
jvans
1
@jvans: Généralement vrai - avec des exceptions notables et des alternatives. J'ai ajouté un paragraphe pour répondre à cela.
Erwin Brandstetter le
2

Selon votre question, vous avez une table avec les champs A et B. Si votre requête est:

SELECT * FROM [YOUR TBL]
WHERE A='XXXX'

L'optimiseur choisira l'index composite pour éviter l'extraction de l'accès aléatoire!

BongSey
la source
-4

C'est dans le cas si vous utilisez juste d'abord dans le prédicat.

Il sera analysé si vous utilisez les premières colonnes de la clé composite et la colonne non-clé de la clé composite.

Pour tromper cela, vous pouvez simplement simuler des prédicats comme celui-ci, puis une colonne non-clé:

[A, B] est votre index, [C] - une autre colonne

Pour utiliser l'index vous écrivez comme:

SELECT
    A,B,C,D,E
FROM 
    test
WHERE
   A=1
AND
   B=B
AND 
   C=3

... pourquoi sélectionne-t-il l'index composite par défaut si l'index A simple est disponible?

Il utilisera index uniquement dans le cas où il y a un ou deux prédicats [A] ou [A], [B]. Il ne l'utilisera pas dans l'ordre [B], [A] ou [A], [C]. Pour pouvoir utiliser l'index avec la colonne supplémentaire [C], vous devez appliquer l'index en ordonnant les prédicats comme suit: [A], [B] et [C].

Farfarak
la source
2
Avec quoi réalisez-vous exactement B=B? Je pense que vous ne réalisez rien et que je rejoins donc toute preuve que ce n'est pas simplement ignoré par l'optimiseur
Jack Douglas
2
B=Best effectivement le même que B IS NOT NULL, ce qui semble déplacé. Certainement pas besoin d'utiliser un index sur (a,b).
Erwin Brandstetter