2009-02-06 3 views
14

Ok, donc je me rends compte que c'est une question assez vague, mais faites attention à moi.Pourquoi une jointure SQL choisit-elle un plan de requête sous-optimal?

J'ai rencontré ce problème à plusieurs reprises avec des requêtes différentes et sans rapport. La requête ci-dessous prend plusieurs minutes pour exécuter:

SELECT <Fields> 
FROM <Multiple Tables Joined> 
    LEFT JOIN (SELECT <Fields> FROM <Multiple Tables Joined>) ON <Condition> 

Cependant, en ajoutant simplement l'indicateur de jointure, il interroge les exécute en quelques secondes:

SELECT <Fields> 
FROM <Multiple Tables Joined> 
    LEFT HASH JOIN (SELECT <Fields> FROM <Multiple Tables Joined>) ON <Condition> 

La chose étrange est le type de REJOIGNEZ spécifié dans la indice n'est pas vraiment ce qui améliore la performance. Il semble être dû au fait que l'indicateur oblige l'optimiseur à exécuter la sous-requête de manière isolée, puis à la joindre. Je vois la même amélioration de performance si je crée une fonction de table (pas en ligne) pour la sous-requête. par exemple. Quelqu'un at-il des idées pour lesquelles l'optimiseur est si bête dans ce cas?

+0

Quelle version de SQL Server utilisez-vous? – Austin

+0

J'ai rencontré le problème à la fois en 2005 et en 2008 –

Répondre

13

Si l'une de ces tables est des variables de table, l'optimiseur utilise une estimation incorrecte de 0 lignes et choisit généralement une boucle imbriquée comme technique de jointure. Il le fait en raison d'un manque de statistiques sur les tables impliquées.

+0

Je n'utilise pas de variables de tableau mais il y a souvent des vues dans la sous-requête. Votre raisonnement a cependant un sens pour moi. –

+1

Lorsque je supprime l'indicateur de jointure, le plan de requête change considérablement et introduit des boucles imbriquées. Je ne peux pas trouver où il fait la mauvaise estimation des lignes mais je ne peux pas passer plus de temps à regarder. –

7

L'optimiseur est un algorithme. Ce n'est pas idiot ou intelligent, ça fonctionne comme il est programmé.

Hash join implique la construction d'une table de hachage sur une source de ligne plus petite, c'est pourquoi la requête interne doit être exécutée en premier.

Dans le premier cas, l'optimiseur a peut-être choisi un nested loop. Il a poussé la condition de jointure dans la requête interne et a exécuté la requête interne à chaque itération avec un prédicat supplémentaire. Il pourrait ne pas trouver un index approprié pour ce prédicat, et un full table scan a eu lieu à chaque itération.

Il est difficile de dire pourquoi cela se produit à moins que vous postez votre requête exacte et combien de lignes sont dans vos tables.

Avec une fonction de table, il est impossible d'insérer une condition de jointure dans la requête interne, c'est pourquoi elle n'est exécutée qu'une seule fois. À l'intérieur de SQL Server 2005: T-SQL Querying répond à ces questions et à beaucoup d'autres.

+0

Je suis d'accord que c'est ce qui semble se passer. Je ne sais pas pourquoi l'optimiseur choisit de faire une boucle imbriquée. –

+0

Il est difficile de dire, nous avons besoin de voir la requête exacte et combien de lignes sont dans les tables. – Quassnoi

+0

J'ai essayé de réduire la requête, mais le plus petit je peux l'obtenir tout en reproduisant le problème est de 43 lignes.Je ne veux pas en souffrir en essayant d'analyser cela sans la base de données. –

-4

L'un des meilleurs aspects sous le capot de la récupération de données T-SQL et du traitement des verbes que j'ai jamais vu. (Non, je ne suis pas un auteur du livre, je ne suis affilié à aucun auteur ou auteur du livre, ni à Microsoft, ni à Microsoft Press.) C'est simplement un travail incroyable, et divers DBAs m'ont tourné vers le passé. quelques années sont d'accord.)

+0

Je connais Itzik - il est probablement l'un des SQL les plus intelligents de la planète. – keithwarren7

Questions connexes