Règle dure et rapide pour inclure des colonnes dans l'index


38

Existe-t-il une règle absolue pour décider quelles colonnes et dans quel ordre elles doivent être placées dans Inclus dans index non clusterisé. Je venais de lire ce post https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index et j'ai constaté que pour la requête suivante:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

Le poster a suggéré de faire un index comme ceci:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

voici ma question pourquoi ne pouvons-nous pas faire un index comme celui-ci

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

ou

    CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

et quoi amène l'affiche à décider de conserver la colonne Nom de famille incluse. Pourquoi pas d'autres colonnes? et comment décider dans quel ordre nous devrions garder les colonnes là?


3
INCLUDE devrait normalement avoir les champs dont vous aurez besoin APRÈS qu'un enregistrement ait été trouvé, ce qui vous évitera un aller-retour pour obtenir plus de données. L'ordre des champs dans INCLUDE n'est pas important.
Jimbo

Ryk, personnellement, je trouve ce post utile.
Jason Young

Je trouve cette question utile aussi. Concentrons-nous sur les bonnes questions et les bonnes réponses au lieu de harceler des individus ....
Volvox

Réponses:


47

Cette suggestion d'index par marc_s est fausse. J'ai ajouté un commentaire. (Et c'était ma réponse acceptée aussi!)

L'index pour cette requête serait

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (Lastname, EmployeeID)

Un index est typiquement

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

Où:

  • KeyColList = Key columns = utilisé pour la restriction de lignes et le traitement de
    WHERE, JOIN, ORDER BY, GROUP BY, etc.
  • NonKeyColList = Colonnes non-clés = utilisées dans SELECT et agrégation (par exemple, SUM (col)) après sélection / restriction

+1 - Je suis d'accord (voir mes ans) que les exemples d'index dans OP ne valent rien pour la requête!
JNK

Génial! Juste une chose de plus qui décidera de l'ordre de KeyColList et de NonKeyColList. Pouvez-vous expliquer avec mon exemple? Supposons maintenant que ma requête est SELECT EmployeeID, DepartmentID, LastName FROM EmployeeWHERE DepartmentID = 5, StateID = 4 Comment serait l'index maintenant?

@Rocky - l' NonKeyColListordre n'a pas d'importance. KeyColListordre devrait être dans l'ordre de fréquence, vous vous attendez à ce qu'ils soient utilisés dans les requêtes. Voir mes notes sur ma réponse ci-dessous, mais c'est comme Last Name, First Name, Middile Initialdans un annuaire téléphonique. Vous avez besoin du premier champ pour trouver le deuxième champ.
JNK

@gbn Avons-nous vraiment besoin de EmployeeID dans la liste d'inclusion? Comme si nous avons un index clusterisé sur EmployeeID Column et au-dessus de cela si nous créons un index non clusterisé sur une colonne DeptId, l'index NonClustered a déjà une référence à la clé de clustering incluse dans la structure Index NonClustered, y compris la clé de clustering dans la liste INCLUDE t ajouter des avantages.
Viswanathan Iyer

1
@ViswanathanIyer ne sera cependant pas ajouté deux fois au stockage sur disque actuel: SQL Server le détecte. Donc, ce n'est pas nécessaire, mais cela rend les choses plus claires. Cependant, nous ne connaissons pas d'index clusterisé dans la question, il est donc plus prudent d'en supposer aucun.
gbn

19

JNK et gbn ont donné d'excellentes réponses, mais il convient également d'envisager la situation dans son ensemble - pas seulement en se concentrant sur une seule requête. Bien que cette requête particulière puisse bénéficier d'un index (# 1):

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

Cet index n'aide pas du tout si la requête change légèrement, par exemple:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

Cela aurait besoin de l'index (# 2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

Imaginez que vous avez 1 000 employés dans le département 5. À l'aide de l'index n ° 1, pour trouver tous les Smiths, vous devez parcourir les 1 000 lignes du département 5, car les colonnes incluses ne font pas partie de la clé. En utilisant l'index n ° 2, vous pouvez rechercher directement le département 5, Nom Smith.

L'index n ° 2 est donc plus utile pour traiter un plus grand nombre de requêtes - mais le coût est une clé d'index plus volumineuse, ce qui agrandit les pages non-feuilles de l'index. Chaque système sera différent, il n'y a donc pas de règle empirique ici.


Notez également que si EmployeeID était la clé de clustering de cette table (en supposant un index clusterisé), vous n'avez pas besoin d'inclure EmployeeID - il est présent dans tous les index non clusterisés, ce qui signifie que l'index n ° 2 pourrait simplement être

Employee(DepartmentID, LastName)

2
+1 pour plus d'informations utiles. Pour votre dernier point, j'ai testé cela et l'utilisation explicite de EmployeeID dans INCLUDE est en fait ignorée (en fonction de la taille de l'index) si EmployeeID est l'index clusterisé. C'est plus évident si je pense et il n'y a pas d'espace négatif.
Gbn

1
Je suis tout à fait d’accord. Mieux vaut toujours être explicite, surtout si cela ne coûte rien!

1
Juste au cas où ... Je veux dire que j'ai testé la clé en cluster dans INCLUDE (pas EmployeeID explicitement) et qu'elle n'ajoute pas d'espace. Dans les colonnes clés, c'est le cas.
gbn

@gbn Oui, la clé de cluster doit uniquement résider au niveau feuille de l'index, c'est-à-dire où résident les colonnes INCLUDE. Le déplacer dans la clé d'index signifierait qu'il existerait également dans les pages non-feuilles. Cela entraînerait un peu de gonflement, mais pas une quantité terrible (sur les pages de niveau intermédiaire, vous ajouteriez 4 octets supplémentaires par page de niveau feuille, en supposant un Integer).

C'est une excellente réponse qui inclut certains des effets décrits dans cet article: sqlperformance.com/2014/07/sql-indexes/… Si votre requête change, il en va de même des exigences de vos index. La réponse de Jim pourrait être meilleure, mais la réponse @gbn vous conviendrait mieux.
John aka hot2use

7

Je ne sais pas comment tu as eu ce premier. Pour moi, pour cette requête, j'utiliserais:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (EmployeeID, Lastname)

Il n'y a pas de "règle absolue" pour pratiquement tout ce qui concerne SQL.

Mais, pour votre exemple, le seul champ utilisé par l'index est DepartmentIDparce qu'il se trouve dans la WHEREclause.

Les autres champs doivent simplement être facilement accessibles à partir de là. Vous sélectionner en fonction DepartmentIDpuis INCLUDEa ces champs au niveau du noeud de feuille de l'index.

Vous ne voulez pas utiliser vos autres exemples car ils ne fonctionneraient pas pour cet index.

Pensez à un index comme un annuaire téléphonique. La plupart des annuaires sont classés par nom de famille, prénom, initiale. Si vous connaissez le prénom d'une personne, mais pas son nom de famille, l'annuaire ne vous sert à rien, car vous ne pouvez pas rechercher le prénom en fonction de l'ordre de son index.

Les INCLUDEchamps ressemblent au numéro de téléphone, à l'adresse, etc., ainsi qu'à d'autres informations pour chaque entrée du livre.

MODIFIER:

Pour clarifier davantage pourquoi ne pas utiliser:

CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

Cet indice est utile si vous avez soit EmployeeIDou BOTH EmployeeID et LastNamedans votre WHEREarticle. C'est à peu près l' opposé de ce dont vous avez besoin pour cette requête.


@ajbeaven c'est vrai, c'est pourquoi le commentaire que j'ai mis dans la modification indique que vous avez besoin de SOOLID employeeID ou des deux colonnes.
JNK

durr désolé, mal lu :(
ajbeaven

0

Je pense que vous pourrez toujours utiliser l'index (employee_id, department_id), mais vous devrez inclure une ligne "factice" dans la phrase where, comme: "employee_id = employee_id)

  • ayant un index sur (employee_id, departemnent_id),
  • avoir à rechercher / restreindre uniquement un département_id
  • sachant qu'il n'utilisera pas l'index depuis le mauvais ordre (ou les choses ont changé maintenant, et le "truc" suivant n'est plus nécessaire. Je suis un "vieux"?) .
  • Utilisez le "vieux" tricK?

    select * from Employee emp
    emp.employee_id = emp.employee_id
    et emp.department_id = 5

(Donc, je ne me concentre pas sur la partie include de Lastname, mais sur le yes / ou la non-utilisation de la clé.)

Sincères amitiés,

Miguell


2
Non, c'est inutile et pas efficace.
ypercubeᵀᴹ

Plus précisément, il faudra toujours effectuer un balayage d'index pour rechercher chaque ID d'employé afin de rechercher toutes les instances de department_id 5. S'il y a 1 000 employés et 5 départements, SQL doit parcourir l'ensemble des 1 000 employés pour rechercher toutes les lignes d'un service particulier.
Mark Sowul

Considérons maintenant le cas contraire (l’index est sur department_id, employee_id). Évidemment, il est facile de trouver un département particulier maintenant, mais notez également que pour trouver un employé particulier, SQL n'a qu'à parcourir 5 départements pour rechercher toutes les lignes d'un employé particulier.
Mark Sowul
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.