Index Seek vs Index Scan

64

En regardant un plan d'exécution d'une requête à exécution lente, j'ai remarqué que certains des nœuds sont à la recherche d'index et que certains d'entre eux sont des analyses d'index.

Quelle est la difference entre and index search et un scan d'index?

Qui fonctionne mieux?

Comment SQL choisit-il l'un sur l'autre?

Je réalise que c’est 3 questions mais je pense que répondre à la première expliquera les autres.

Greg
la source
6
Vous avez une bonne référence sur use-the-index-luke .
Marian
7
Toutes les analyses ne sont pas mauvaises - c'est parfois le moyen le plus efficace de satisfaire la requête. Notez également que toutes les recherches ne sont pas des recherches - elles sont souvent en réalité des analyses de plage, et que la recherche indique uniquement comment cela est arrivé au début de la plage.
Aaron Bertrand
@AaronBertrand, mais si vous obtenez le début de la plage et le lisez, cela signifie essentiellement que vous avez besoin des données de toute façon. En outre, il cherche la fin de la gamme.
George Polevoy

Réponses:

76

Version courte: chercher c'est beaucoup mieux

Version plus courte: chercher est généralement beaucoup mieux, mais beaucoup de recherches (causées par une mauvaise conception de requête avec des sous-requêtes corrélées par exemple, ou parce que vous effectuez beaucoup de requêtes dans une opération de curseur ou une autre boucle) peuvent être pires scan, en particulier si votre requête peut renvoyer des données de la plupart des lignes de la table affectée.

Il est utile de couvrir toute la famille pour les opérations de recherche de données afin de bien comprendre les implications en termes de performances.

Analyses de table: En l'absence d'index pertinents pour votre requête, le planificateur est obligé d'utiliser une analyse de table, ce qui signifie que chaque ligne est examinée. Cela peut entraîner la lecture de toutes les pages relatives aux données de la table à partir du disque, ce qui est souvent le cas le plus défavorable. Notez que pour certaines requêtes, il utilisera une analyse de table même lorsqu'un index utile est présent - ceci est généralement dû au fait que les données dans la table sont si petites qu'il est plus fastidieux de parcourir les index (si c'est le cas, vous vous attendriez à ce que prévoir de changer à mesure que les données augmentent, en supposant que la mesure de sélectivité de l’indice est bonne).

Balayages d'index avec recherches de lignes: aucun index pouvant être utilisé directement pour une recherche n'est trouvé, mais un index contenant les colonnes de droite est présent, un balayage d'index peut être utilisé. Par exemple, si vous avez une grande table avec 20 colonnes avec un index sur column1, col2, col3 et vous émettez SELECT col4 FROM exampletable WHERE col2=616, dans ce cas, il col2est préférable d'analyser l' index à interroger que d'analyser l'intégralité de la table. Une fois que les lignes correspondantes ont été trouvées, les pages de données doivent être lues dans la colonne de collecte 4 pour la sortie (ou la jonction ultérieure), ce qui correspond à l'étape de "recherche de signet" lorsque vous la voyez dans les plans de requête.

Analyses d'index sans recherche de ligne: si l'exemple ci-dessus était, SELECT col1, col2, col3 FROM exampletable WHERE col2=616l'effort supplémentaire de lecture de pages de données n'est pas nécessaire: une fois que les lignes d'index correspondant col2=616sont trouvées, toutes les données demandées sont connues. C'est pourquoi vous voyez parfois des colonnes qui ne feront jamais l'objet d'une recherche, mais qui sont susceptibles d'être demandées pour une sortie, ajoutées à la fin des index - cela peut enregistrer des recherches de lignes. Lorsque vous ajoutez des colonnes à un index pour cette raison et uniquement pour cette raison, ajoutez-les avec la INCLUDEclause pour indiquer au moteur qu'il n'a pas besoin d'optimiser la présentation de l'index pour l'interrogation basée sur ces colonnes (cela peut accélérer les mises à jour apportées à ces colonnes). . Les analyses d'index peuvent également résulter de requêtes sans clause de filtrage: SELECT col2 FROM exampletableanalysera cet exemple d'index au lieu des pages de table.

Recherche d'index (avec ou sans recherche de ligne) : Dans une recherche, tout l'index n'est pas pris en compte. Pour la requête, SELECT * FROM exampletable WHERE c1 BETWEEN 1234 AND 4567le moteur de requête peut trouver la première ligne qui correspond en effectuant une recherche arborescente sur l'index, c1puis naviguer dans l'index dans l'ordre jusqu'à ce qu'il atteigne la fin de la plage (il en va de même avec une requête pour c1=1234que il pourrait y avoir plusieurs lignes correspondant à la condition même pour une =opération). Cela signifie que seules les pages d'index pertinentes (plus quelques-unes nécessaires à la recherche initiale) doivent être lues à la place de toutes les pages de l'index (ou de la table).

Index clusterisés: avec un index clusterisé, les données de la table sont stockées dans les nœuds terminaux de cet index au lieu d'être dans une structure de segment de mémoire séparée. Cela signifie qu'il ne sera jamais nécessaire de rechercher des lignes supplémentaires après avoir trouvé des lignes utilisant cet index, quelles que soient les colonnes nécessaires [sauf si vous disposez de données hors page telles que des TEXTcolonnes ou des VARCHAR(MAX)colonnes contenant des données longues].

Vous ne pouvez avoir qu'un seul index clusterisé pour cette raison [1] , il est votre table au lieu d'une structure de pile distincte. Ainsi, si vous utilisez l'un [2], choisissez avec soin l'emplacement où vous le placez pour obtenir un gain maximal.

Notez également que l'index clusterisé est la "clé de clustering" de la table et qu'il est inclus dans tous les index non clusterisés de la table. Par conséquent, un index clusterisé étendu n'est généralement pas une bonne idée.

[1] En fait, vous pouvez effectivement avoir plusieurs index en cluster en définissant des index non en cluster qui couvrent ou incluent toutes les colonnes de la table, mais cela risque de gaspiller de l’espace et d’avoir un impact sur les performances en écriture. Si vous envisagez de le faire, assurez-vous vous avez vraiment besoin de.

[2] Quand je dis « si vous utilisez un index ordonné en clusters », font remarquer qu'il est généralement recommandé de faire avoir un sur chaque table. Il existe des exceptions, comme pour toutes les règles empiriques, les tables ne contenant que des insertions en bloc et des lectures non ordonnées (les tables de transfert pour les processus ETL, par exemple) étant l'exemple de compteur le plus courant.

Point supplémentaire: Scans incomplets:

Il est important de se rappeler que, selon le reste de la requête, une analyse table / index peut ne pas analyser la totalité de la table. Si la logique le permet, le plan de requête peut éventuellement entraîner son abandon précoce. L'exemple le plus simple est celui-ci SELECT TOP(1) * FROM HugeTable: si vous regardez le plan de requête, vous verrez qu'une seule ligne a été renvoyée de l'analyse et si vous regardez les statistiques d'E / S ( SET STATISTICS IO ON; SELECT TOP(1) * FROM HugeTable), vous verrez qu'il ne lit qu'un très petit nombre. de pages (peut-être un seul).

La même chose peut se produire si le prédicat d'une clause WHEREou JOIN ... ONpeut être exécuté simultanément à l'analyse qui est la source de ses données. Le planificateur / gestionnaire de requêtes peut parfois être très intelligent pour renvoyer les prédicats vers les sources de données afin de permettre une interruption précoce des analyses de cette manière (et parfois, vous pouvez être habile pour réorganiser les requêtes afin de l'aider à le faire!). Alors que les données circulent de droite à gauche, comme indiqué par les flèches dans l'affichage du plan de requête standard, la logique s'exécute de gauche à droite et chaque étape (de droite à gauche) ne s'exécute pas nécessairement complètement avant le début suivant. Dans l'exemple ci-dessus, si vous regardez chaque bloc du plan de requête en tant qu'agent, l' SELECTagent demande à l' TOPagent une ligne qui, à son tour, demande àTABLE SCANagent pour un, puis l' SELECTagent en demande un autre, mais l' TOPagent sait qu'il n'est pas nécessaire de demander au lecteur de la table, l' SELECTagent obtient une réponse "rien n'est plus pertinent" et sait que tout le travail est fait. De nombreuses opérations bloquent ce genre d'optimisation bien sûr si souvent dans les exemples plus complexes une analyse de table / index vraiment ne lisent chaque ligne, mais attention à ne pas sauter à la conclusion que toute analyse doit être une opération coûteuse.

David Spillett
la source
6

Généralement, les recherches sont bonnes, les analyses sont mauvaises.

Les recherches sont les endroits où la requête peut utiliser efficacement l'index et l'utilisent pour trouver les lignes dont il a besoin.

Les analyses sont les endroits où la requête parcourt l’ensemble de l’index en essayant de trouver ce dont elle a besoin.

Comment SQL choisit-il? Au fond de l'optimiseur de requêtes, la décision est prise en fonction de votre requête, des index disponibles et des informations statistiques associées à ces index.

Il y a quelques livres à lire qui pourraient présenter un intérêt ici - tous deux à la librairie Red-Gate à l' adresse http://www.red-gate.com/community/books/

  • Plans d'exécution SQL Server de Grant Fritchey
  • À l'intérieur de l'optimiseur de requêtes de Benjamin Nevarez
  • Statistiques SQL Server par Holger Schmeling
Thomas Rushton
la source
7
Pour le même plan, une analyse de table unique est une bonne chose, un million de recherches est une mauvaise chose. Votre première déclaration n’est donc pas tout à fait correcte.
Marian
En effet, la recherche d'index et l'analyse d'index ont chacune leur propre utilisation, vous ne pouvez pas dire que l'une est meilleure qu'une autre SANS le contexte des tables et des requêtes sous-jacentes. La plupart du temps, si une statistique de la table est inexacte, le plan d'exécution peut apparaître sous-optimal, par exemple une recherche d'index est choisie par erreur sur une analyse d'index et vice versa.
Jyao
5

Si vous souhaitez creuser le sujet, un livre très utile (du moins pour moi) est SQL Server Execution Plans de Grant Fritchey, disponible gratuitement sur RedGate ici .

Si vous avez une requête telle que

SELECT *
FROM myTable

SQL Server utilisera probablement une analyse d'index, car elle doit parcourir toutes les lignes pour afficher les résultats requis.

Au contraire,

SELECT *
FROM myTable
WHERE myID = 1

entraînera certainement une recherche dans l’index. SQL Server utilisera la structure B-tree de l'index myID et l'extraction de la ligne appropriée sera beaucoup plus rapide.

KookieMonster
la source
Je ne sais pas si je suis d'accord avec "certainement" - même si un index a pour identifiant mon ID, une recherche peut ne pas être la réponse optimale (dépend de nombreux facteurs, tels que son caractère unique, qui peut être true dans la table customers mais pas pour customerID dans la table orders, combien de colonnes doivent être couvertes mais ne sont pas dans l'index, etc.).
Aaron Bertrand
Je ne pense pas que cette réponse couvre vraiment les questions posées.
Zero3
5

D'autres ont assez bien défini les différences entre recherche et analyse. Dans ce cas, votre requête elle-même et le planificateur d'exécution doivent vous fournir les informations dont vous avez besoin pour connaître les valeurs utilisées comme prédicats (filtres) pour la requête dans chaque partie. En règle générale, il est recommandé de toujours ajouter des index non clusterisés sur des clés étrangères et, en fonction des cas d'utilisation décrits dans le code du programme, vous pouvez également envisager de créer d'autres index multi-colonnes ou des index de colonnes inclus. Avec la terminologie présentée ici, une recherche google donnera des résultats décents sur des exemples sur chacun.

Mais à titre d'exemple, supposons que votre code interroge les colonnes A et B sur des filtres donnés, mais que vous souhaitiez également renvoyer les valeurs des colonnes C et E, vous souhaiterez peut-être créer un index sur les colonnes A et B avec INCLUDE. option contenant les colonnes C et E. Ainsi, une recherche d'index unique renverra tout ce dont vous avez besoin, car il n'est pas nécessaire d'effectuer une recherche pour extraire les autres valeurs (C et E) sur la même ligne.

Kahn
la source