Pour une requête moyennement complexe que j'essaie d'optimiser, j'ai remarqué que la suppression de la TOP n
clause modifie le plan d'exécution. J'aurais supposé que lorsqu'une requête incluait TOP n
le moteur de base de données, la requête serait exécutée en ignorant la TOP
clause puis, à la fin, réduirait simplement le résultat défini au nombre n de lignes demandé. Le plan d'exécution graphique semble indiquer que c'est le cas - TOP
c'est la "dernière" étape. Mais il semble qu'il se passe plus de choses.
Ma question est la suivante: comment (et pourquoi) une clause TOP n at-elle un impact sur le plan d’exécution d’une requête?
Voici une version simplifiée de ce qui se passe dans mon cas:
La requête met en correspondance les lignes de deux tables, A et B.
Sans la TOP
clause, l'optimiseur estime qu'il y aura 19k lignes de la table A et 46k de la table B. Le nombre réel de lignes renvoyées est de 16k pour A et de 13k pour B. Une correspondance de hachage est utilisée pour associer ces deux résultats total de 69 lignes (un tri est alors appliqué). Cette requête se produit très rapidement.
Lorsque j'ajoute TOP 1001
l'optimiseur n'utilise pas de correspondance de hachage; au lieu de cela, il trie d'abord les résultats de la table A (même estimation / valeur réelle de 19 k / 16 k) et crée une boucle imbriquée contre la table B. Le nombre estimé de lignes pour la table B est maintenant égal à 1 et il est étrange que cela TOP n
affecte nombre estimé d'exécutions (recherche d'index) contre B - il semble toujours être 2n + 1 , ou dans mon cas 2003. Cette estimation change en conséquence si je change TOP n
. Bien entendu, puisqu'il s'agit d'une jointure imbriquée, le nombre réel d'exécutions est de 16 000 (le nombre de lignes de la table A), ce qui ralentit la requête.
Le scénario actuel est un peu plus complexe, mais il capture l’idée / le comportement de base. La recherche dans les deux tables s'effectue à l'aide de recherches d'index. Ceci est l'édition SQL Server 2008 R2 Enterprise.
ORDER BY
clause. Ajout deTOP
modifications là où cela se produit dans le plan, mais je suis plus préoccupé par la manière dont il affecte le nombre d'exécutions de recherches d'index sur la table B ... (bien sûr, les deux peuvent être liées - je ne sais pas)FAST num_rows
indicateur de requête.Réponses:
La formulation de ce qui précède me fait penser que vous pouvez avoir une image mentale incorrecte de la façon dont une requête s'exécute. Un opérateur dans un plan de requête n'est pas une étape (l'ensemble des résultats d'une étape précédente est évalué par la suivante.
SQL Server utilise un modèle d'exécution en pipeline , dans lequel chaque opérateur expose des méthodes telles que Init () , GetRow () et Close () . Comme le suggère le nom GetRow () , un opérateur génère une ligne à la fois à la demande (à la demande de son opérateur parent). Ceci est documenté dans la référence de la documentation en ligne , Opérateurs physiques et logiques , avec des informations plus détaillées dans mon article de blog Pourquoi les plans de requête sont-ils inversés ? Ce modèle de rangée à la fois est essentiel pour former une intuition solide pour l'exécution de requêtes.
Certaines opérations logiques, telles que les
TOP
semi-jointures et l'FAST n
indicateur de requête, affectent la manière dont l'optimiseur de requêtes calcule les variantes du plan d'exécution. L'idée de base est qu'une forme de plan possible peut renvoyer les n premières lignes plus rapidement qu'un plan différent optimisé pour renvoyer toutes les lignes.Par exemple, la jointure de boucles imbriquées indexées est souvent le moyen le plus rapide de renvoyer un petit nombre de lignes, bien que la jointure de hachage ou de fusion avec des analyses puisse être plus efficace sur des ensembles plus volumineux. L'optimiseur de requêtes raisonne ces choix en définissant un objectif de ligne à un point particulier de l'arborescence logique des opérations.
Un objectif de ligne modifie le mode de calcul du coût des alternatives du plan de requête. L’essentiel est que l’optimiseur commence par chiffrer le coût de chaque opérateur comme si l’ensemble des résultats était requis, puis fixait un objectif de ligne au point approprié, puis redescendait l’arborescence du plan en estimant le nombre de lignes qu’il devait examiner. pour atteindre l'objectif de la ligne.
Par exemple, une logique
TOP(10)
définit un objectif de ligne de 10 à un point particulier de l'arborescence de la requête logique. Les coûts des opérateurs menant à l'objectif de la ligne sont modifiés pour estimer le nombre de lignes à produire pour atteindre l'objectif de la ligne. Ce calcul peut devenir complexe, il est donc plus facile de comprendre tout cela avec un exemple entièrement travaillé et des plans d'exécution annotés. Les objectifs de ligne peuvent affecter davantage que le type de jointure ou si les recherches et les recherches sont préférées aux analyses. Plus de détails à ce sujet ici .Comme toujours, un plan d'exécution sélectionné sur la base d'un objectif de rangée est soumis aux capacités de raisonnement de l'optimiseur et à la qualité des informations qui lui sont fournies. Tous les plans avec un objectif de rangée ne produiront pas le nombre de rangées requis plus rapidement dans la pratique, mais selon le modèle de calcul des coûts, ce sera le cas.
Lorsqu'un plan d'objectif de ligne ne s'avère pas plus rapide, il existe généralement des moyens de modifier la requête ou de fournir de meilleures informations à l'optimiseur de manière à optimiser le plan sélectionné naturellement. Quelle option est appropriée dans votre cas dépend des détails bien sûr. La fonctionnalité d'objectif de ligne est généralement très efficace (bien qu'un bogue soit à surveiller lorsqu'il est utilisé dans des plans d'exécution parallèles).
Votre requête et votre plan particuliers peuvent ne pas convenir à une analyse détaillée ici (vous fournirez certainement un plan d’exécution réel si vous le souhaitez), mais nous espérons que les idées exposées ici vous permettront d’avancer.
la source
Lorsque vous utilisez TOP, l’optimiseur voit une possibilité de faire moins de travail. Si vous demandez 10 lignes, il y a de fortes chances qu'il n'ait pas besoin de consommer l'ensemble. Ainsi, l'opérateur TOP peut être poussé beaucoup plus loin vers la droite. Il continuera à demander des lignes à l'opérateur suivant (sur sa droite) jusqu'à ce qu'il en ait reçu suffisamment.
Vous soulignez que sans TOP, la requête trie les données à la toute fin. Si le moteur pouvait savoir à l'avance combien de lignes allaient être satisfaites par la jointure, il pourrait bien choisir d'utiliser un plan similaire, en plaçant le TOP en haut à gauche. Mais avec l’effort de faire une correspondance de hachage étant relativement élevé, et probablement sans option pour une jointure de fusion, l’Optimizer pourrait préférer filtrer le TOP plus à droite.
Lorsque la table B est interrogée, elle récupère une seule ligne à la fois. C'est pourquoi l'estimation est 1. Cela suppose également que cette ligne ne sera trouvée que 50% du temps. Donc, il suppose que 2n + 1 aura besoin de le trouver.
la source
TOP
clause? Merci pour votre réponse / patience.