Le plan d'exécution de la requête SQL Server indique un «nombre de lignes réel» incorrect sur un index utilisé et les performances sont terriblement lentes

StackOverflow https://stackoverflow.com/questions/225309

Question

Aujourd'hui, je suis tombé sur un problème de performance intéressant avec une procédure stockée s'exécutant sur SQL Server 2005 SP2 dans une base de données s'exécutant au niveau compatible 80 (SQL2000).

Le processus dure environ 8 minutes et le plan d'exécution montre l'utilisation d'un index avec un nombre de lignes réel de 1.339.241.423, ce qui est environ 1 000 fois supérieur au "réel". nombre de lignes réel de la table elle-même, qui est 1.144.640, comme indiqué correctement par le nombre estimé de lignes. Le nombre de lignes réel indiqué par l'optimiseur de plan de requête est donc totalement faux!

alt text

Fait intéressant, lorsque je copie les valeurs du paramètre procs à l’intérieur du proc et que j’utilise les variables locales dans la requête réelle, tout fonctionne correctement - le proc s’exécute en 18 secondes et le plan d’exécution indique le nombre exact de lignes réelles.

MODIFIER: Comme suggéré par TrickyNixon, cela semble être un signe du problème de détection de paramètre. Mais en réalité, dans les deux cas, je reçois exactement le même plan d’exécution. Les mêmes indices sont utilisés dans le même ordre. La seule différence que je vois est le moyen d’obtenir un nombre de lignes réel élevé sur l’index PK_ED_Transitions lors de l’utilisation directe des parametervalues.

J'ai déjà fait dbcc dbreindex et UPDATE STATISTICS sans succès. dbcc show_statistics affiche également de bonnes données pour l'index.

Le proc est créé avec RECOMPILE afin qu’il soit compilé chaque fois qu’il exécute un nouveau plan d’exécution.

Pour être plus précis, celui-ci est rapide:

CREATE  Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE 
as

set nocount on

declare @local datetime
set @local = @Param

select 
some columns
from 
table1
where
column = @local
group by
some other columns

Et cette version est terriblement lente, mais produit exactement le même plan d'exécution (en plus du nombre de lignes trop élevé sur un index utilisé):

CREATE  Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE 
as

set nocount on

select 
some columns
from 
table1
where
column = @Param
group by
some other columns

Des idées? Quelqu'un sait-il où Sql Server obtient la valeur réelle du nombre de lignes lors du calcul des plans de requête?

Mise à jour : j'ai essayé la requête sur un autre serveur avec le mode Copat défini sur 90 (Sql2005). C'est le même comportement. Je pense que je vais ouvrir un appel de support MS, parce que cela me ressemble à un bug.

Était-ce utile?

La solution

Ok, enfin je suis arrivé moi-même.

Les deux plans de requête sont différents dans un petit détail que j'ai raté au début. le plus lent utilise un opérateur de boucles imbriquées pour joindre deux sous-requêtes. Et cela se traduit par le nombre élevé de lignes en cours sur l'opérateur d'analyse d'index, qui est simplement le résultat de la multiplication du nombre de lignes de l'entrée a avec le nombre de lignes de l'entrée b.

Je ne sais toujours pas pourquoi l'optimiseur décide d'utiliser les boucles imbriquées au lieu d'une correspondance de hachage qui exécute une minuterie plus rapide dans ce cas, mais je pourrais gérer mon problème en créant un nouvel index, de sorte que le moteur effectue une index search statt au lieu d’un balayage d’index sous les boucles imbriquées.

Autres conseils

Lorsque vous vérifiez les plans d'exécution du processus stocké par rapport à la requête copier / coller, utilisez-vous les plans estimés ou les plans réels? Assurez-vous de cliquer sur Requête, Inclure le plan d'exécution, puis exécutez chaque requête. Comparez ces plans et voyez quelles sont les différences.

Cela ressemble à un cas de Parameter Sniffing. Voici une excellente explication ainsi que les solutions possibles: Je sens un paramètre!

Voici un autre thread StackOverflow qui l’adresse: Détection de paramètre (ou spoofing) dans SQL Server

Pour moi, cela semble toujours comme si les statistiques étaient incorrectes. La reconstruction des index ne les met pas nécessairement à jour.

Avez-vous déjà essayé d'utiliser un UPDATE STATISTICS explicite pour les tables concernées?

Avez-vous exécuté sp_spaceused pour vérifier si SQL Server dispose du résumé approprié pour cette table? Je crois que dans SQL 2000, le moteur utilisait ce type de métadonnées lors de la création de plans d'exécution. Auparavant, nous devions exécuter DBCC UPDATEUSAGE toutes les semaines pour mettre à jour les métadonnées de certaines tables évoluant rapidement, SQL Server choisissant de mauvais index en raison de données de nombre de lignes incorrectes.

Vous utilisez SQL 2005 et BOL indique qu'en 2005, vous ne devriez plus utiliser UpdateUsage, mais comme vous êtes en mode 2000, vous constaterez qu'il est toujours nécessaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top