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 col2
est 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=616
l'effort supplémentaire de lecture de pages de données n'est pas nécessaire: une fois que les lignes d'index correspondant col2=616
sont 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 INCLUDE
clause 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 exampletable
analysera 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 4567
le moteur de requête peut trouver la première ligne qui correspond en effectuant une recherche arborescente sur l'index, c1
puis 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=1234
que 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 TEXT
colonnes 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 WHERE
ou JOIN ... ON
peut ê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' SELECT
agent demande à l' TOP
agent une ligne qui, à son tour, demande àTABLE SCAN
agent pour un, puis l' SELECT
agent en demande un autre, mais l' TOP
agent sait qu'il n'est pas nécessaire de demander au lecteur de la table, l' SELECT
agent 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.