web-dev-qa-db-fra.com

Dois-je avoir besoin d'index séparés pour chaque type de requête ou un index de plusieurs colonnes fonctionne-t-il?

Je connais un peu la réponse à cette question déjà, mais je me sens toujours comme si vous avez plus de choses que j'ai besoin de ramasser sur le sujet.

Ma compréhension de base est qu'une seule parole, un indice unique qui inclut tous les champs que vous pourriez interroger/trier à tout moment n'est pas susceptible d'être utile, mais j'ai déjà vu ce type de chose. Comme dans, quelqu'un pensait: "Eh bien, si nous venons de mettre tout ce genre de choses dans un indice, la base de données peut l'utiliser pour trouver ce dont il a besoin", sans avoir jamais vu de plan d'exécution pour que certaines des requêtes réelles soient exécutées.

Imaginez une table comme si:

id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime

Je pourrais voir un seul index, y compris les name, customerId et dateCreated champs.

Mais ma compréhension est qu'un tel indice ne serait pas utilisé dans une requête comme, par exemple:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Pour une telle requête, il me semble qu'une meilleure idée serait un index comprenant les champs customerId et dateCreated champs, avec le champ customerId étant "d'abord". Cela créerait un indice qui aurait les données organisées de manière à ce que cette requête puisse trouver rapidement ce dont elle a besoin - dans l'ordre qu'il a besoin.

Une autre chose que je vois, peut-être aussi fréquemment que la première, est des index individuels sur chaque champ; Donc, une chacune sur name, customerId et dateCreated champs.

Contrairement au premier exemple, ce type d'arrangement me semble parfois être au moins partiellement utile; Le plan d'exécution de la requête peut montrer qu'au moins, il utilise l'index sur le customerId pour sélectionner les enregistrements, mais il n'utilise pas l'index avec le champ dateCreated pour les trier.


Je sais que c'est une question large, car la réponse spécifique à une requête particulière sur tout ensemble particulier de tableaux est généralement de voir ce que le plan d'exécution dit que cela va faire et, autrement, prenez les spécificités de la table (s) et des requêtes dans Compte. De plus, je sais que cela dépend de la fréquence à laquelle une requête pourrait être exécutée par opposition à la surcharge de maintenir un index particulier pour cela.

Mais je suppose que ce que je demande, c'est comme un "point de départ" général pour les index, l'idée d'avoir des index spécifiques pour des requêtes spécifiques et fréquemment tirées et les champs de l'endroit ou de la commande par des clauses ont un sens?

22
Andrew Barber

Vous avez raison dans la mesure où votre exemple requête n'utiliserait pas cet index.

Le planificateur de requêtes envisagera d'utiliser un index si:

  • tous les champs contenus sont référencés dans la requête
  • certains des champs à partir du début sont référencés

Il ne sera pas en mesure d'utiliser des index qui commencent par un champ non utilisé par la requête.

Donc pour votre exemple:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

il considérerait des index tels que:

[customerId]
[customerId], [dateCreated]
[customerId], [dateCreated], [name]

mais non:

[name], [customerId], [dateCreated]

Si cela a trouvé à la fois [customerId] Et [customerId], [dateCreated], [name] Sa décision de préférer l'un sur l'autre dépendrait des statistiques d'index qui dépendent des estimations de la balance des données dans les champs. Si [customerId], [dateCreated] A été défini, il devrait préférer que sur les deux autres sauf si vous donnez un indice d'index spécifique au contraire.

Il n'est pas rare de voir un indice défini pour chaque domaine de mon expérience, que cela soit rarement optimal que la gestion supplémentaire nécessaire pour mettre à jour les index sur insertion/mise à jour, et l'espace supplémentaire nécessaire pour les stocker, est gaspillé lorsque la moitié de Ils ne peuvent jamais être utilisés - mais à moins que votre DB ne voit que des charges lourdes, les performances ne vont pas trop puer même avec les index en excès.

Des index spécifiques pour des requêtes fréquentes qui seraient autrement lents en raison de la numérisation de table ou d'indexe, c'est généralement une bonne idée, bien que vous n'en faites pas trop, comme vous pouviez échanger un problème de performance pour un autre. Si vous définissez [customerId], [dateCreated] En tant qu'index, vous rappelez-vous que le planificateur de requêtes sera en mesure d'utiliser cela pour des requêtes qui utiliseraient un index sur simplement [customerId] Si présent. Tout en utilisant simplement [customerId] Serait légèrement plus efficace que l'utilisation de l'indice composé qui peut être atténuée en finissant par avoir deux index en compétition pour l'espace dans RAM au lieu d'un (cependant si votre L'ensemble du jeu de travail normal s'intègre facilement dans RAM Ce concours de mémoire supplémentaire peut ne pas être un problème).

27
David Spillett

Pour répondre à votre question originale, oui, les index doivent être conçus autour du requêtes, pas seulement le tablea. L'ordre des champs dans l'index est d'une importance vitale. Concevoir un seul index Pour être optimal pour plusieurs requêtes est plus difficile, et vous devrez faire des compromis.

En ce qui concerne votre deuxième point, oui, un groupe d'index sur des champs individuels célibataires est ennuyeux. Je vois tout le temps dans mon environnement, et c'est généralement un drapeau rouge pour moi que l'équipe de développement n'a pas travaillé avec un DBA pour concevoir des indices appropriés.

Ma stratégie pour la conception d'index, est d'indexer:

  • Champs utilisés dans où (par ordre de sélectivité)
  • Champs utilisés dans l'ordre par
  • Inclure d'autres champs (si nécessaire) pour faire un index de couverture

Donc pour votre exemple:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Je concevrais probablement un indice sur (CustomerID, DateCreated) Inclure (ID, Nom). Cet indice de couverture signifie que la requête n'a jamais besoin de toucher la table d'origine, d'améliorer considérablement les performances.

Cet exemple est presque aussi simple, cependant. Un indice naïf sur Just (CustomerID) fonctionnerait presque aussi bien (en supposant que chaque client possède uniquement un seul représentant, alors qu'un seul signet recherche de la table sera requis). Il peut également être également avantageux de faire un indice clustered indice sur (CustomerID, ID), en fonction de quelles autres requêtes contre la table.

6
BradC