Machines SQL Server 2005 identiques (?); la requête prend 2 secondes sur l'un, 15 minutes sur l'autre

12

L'environnement:

Nous avons deux machines Windows Server 2003 R2 32 bits exécutant SQL Server 2005. Les configurations matérielles sont des serveurs identiques avec un processeur Xeon 5160, 4 Go de RAM et 13 Go de RAID0. Les drapeaux AWE et / 3GB ne sont pas activés.

Les serveurs ont été configurés côte à côte à l'aide d'une liste de contrôle d'installation prédéfinie, et TOUS les logiciels installés sont les mêmes sur les deux machines.

Chaque paramètre d'installation de SQL Server et chaque niveau de correctif que nous savons vérifier sont identiques. Une différence est que TEMPDB est de 400 Mo sur la machine rapide et 1,2 Go sur la machine lente. Cependant, dans les deux cas, nous ne voyons aucune allocation TEMPDB en cours.

Le problème:

Il existe une procédure stockée qui s'exécute en 2 secondes sur l'un, mais 15 minutes sur l'autre. Pendant les 15 minutes supplémentaires, il y a peu ou pas d'activité sur le disque, aucun changement d'utilisation de la mémoire, mais un cœur de processeur est épinglé à 100% tout le temps.

Ce comportement persiste même lorsque les bases de données sont sauvegardées de l'une et restaurées sur l'autre.

Puisqu'il s'agit d'une procédure stockée, le moniteur d'activité et le profileur ne nous montrent aucun détail sur l' endroit où la procédure stockée se déroule.

La question:

Que devrions-nous regarder d'autre?

Suivre:

La lenteur se produit dans les instructions FETCH NEXT pour la définition de curseur suivante:

DECLARE C CURSOR FOR
    SELECT X, Y
    FROM dbo.A
    WHERE X NOT IN (SELECT X FROM dbo.B)
    AND Z <=0
...
<snip>
...
FETCH NEXT FROM C INTO @X, @Y
FETCH NEXT FROM C INTO @X, @Y
...

Chacune des instructions FETCH - sur une table contenant seulement environ 1000 lignes - nécessite environ 7,25 minutes. (Non, je ne sais pas pourquoi il en fait deux de suite, il faut demander aux développeurs, mais il fonctionne correctement sur les deux serveurs).

Je suis un peu méfiant de ce "PAS DANS (SÉLECTIONNER ...)", car il semble que les lectures virtuelles soient vraiment élevées.

ryandenki
la source
Comment les enregistrements dans dbo.B et dbo.BX sont-ils indexés?
Mark Storey-Smith
1
Je suis curieux de savoir s'il y aurait une différence de performances si vous y alliez: sélectionnez dbo.ax, dbo.ay dans dbo.a, jointure externe gauche dbo.b sur dbo.ax = dbo.bx où dbo.bx est nul et z <= 0
DForck42
Une pensée de plus à jeter dans le mix. Êtes-vous certain que le ralentissement est dû à l'extraction du curseur? Le déterminez-vous à partir du plan d'exécution (qui concerne uniquement les estimations) ou à partir d'une trace de profil?
Mark Storey-Smith,
C'est à partir d'une trace de profil.
ryandenki
Les plans d'exécution sont-ils les mêmes? Il est possible que l'un d'eux utilise un mauvais plan d'exécution.
Zane

Réponses:

7

L'utilisation d'une méthodologie de dépannage des performances comme les attentes et les files d'attente identifie la raison de la consommation élevée du processeur, puis une action appropriée peut être recommandée une fois le goulot d'étranglement identifié.

Remus Rusanu
la source
6

SQL Server sélectionne un plan différent sur l'autre case.

La restauration supprimera généralement les problèmes basés sur les statistiques, donc je regarderais les différences de serveur.

Quelques vérifications grossières en premier. Ne présumez pas: vérifiez

  • Vérifiez que les paramètres de SQL Server sont les mêmes dans sys.configuration, par exemple degré maximum ou parallélisme
  • Exécutez DBCC USEROPTIONS pour voir si les paramètres ANSI sont différents au moment de l'exécution (les paramètres ANS peuvent affecter le plan choisi)
  • Vérifiez les journaux Windows et SQL Server pour voir s'il y a des problèmes

Sautez ensuite à l'extrémité profonde, selon la réponse de Remus.

gbn
la source
Merci pour les indices. Les configurations sys.configuration et DBCC USEROPTIONS sont identiques entre les deux machines. Aucune erreur ou avertissement dans les journaux Windows ou SQL Server.
1
Et ils exécutent également la disposition de base de données identique? Aucun plan administrateur ne faisant des optimisations sur (reconstruction d'index, etc.), les bases de données ont les mêmes statistiques pour les objets pertinents et la même disposition de disque? Même niveau de patch?
TomTom
Oui, même disque, disposition de base de données et niveau de correctif. En fait, la base de données sur la machine rapide est une sauvegarde restaurée de la machine lente. Et il n'y a pas de plans d'administration qui varient, pour autant que je puisse voir.
ryandenki
6

Si toutes les autres choses sont égales, il est probable (selon la réponse de @ gbn) qu'un plan d'exécution différent soit généré sur chaque serveur. Comme exercice académique, il serait intéressant de voir les deux plans, alors récupérez-les dans le cache du plan sur chaque serveur et ajoutez-les à votre question si possible. Nous pouvons alors identifier les différences dans les plans qui provoquent une si grande variation de performance.

Pour une solution rapide, jetez un œil à l' astuce USE PLAN . Cela permet d'attacher le bon plan du serveur rapide à la procédure stockée sur le serveur lent.

Edit: mise à jour suivante re: curseur

Une autre variation sur votre requête pour essayer que je ne vois pas mentionnée dans d'autres réponses:

DECLARE C CURSOR FOR
    SELECT X, Y
    FROM dbo.A
    WHERE NOT EXISTS (SELECT 1 FROM dbo.B WHERE dbo.B.X = dbo.A.X)
    AND Z <=0
...
<snip>
...
FETCH NEXT FROM C INTO @X, @Y
FETCH NEXT FROM C INTO @X, @Y
Mark Storey-Smith
la source
C'est un bon conseil, nous vérifions les plans de requête. En fait, le ralentissement de la procédure stockée semble être lié à un curseur. Voir modifier.
ryandenki
4

Faites-moi plaisir et essayez de remplacer:

DECLARE C CURSOR FOR
SELECT X, Y
FROM dbo.A
WHERE X NOT IN (SELECT X FROM dbo.B)
AND Z <=0

avec ça:

DECLARE C CURSOR FOR
SELECT 
    X, 
    Y
FROM dbo.A

    LEFT OUTER JOIN dbo.B
        ON dbo.A.X = dbo.b.X

WHERE dbo.B.X IS NULL
AND Z <=0

Je ne pense pas que cela devrait se manifester comme un problème de performances dans la partie FETCH NEXT FROM de votre code, mais je n'ai pas encore reçu mon injection de caféine. Essayez ma suggestion et faites-le moi savoir.

J'espère que cela t'aides,

Mat

Matt M
la source
4

Vérifiez vos index et mettez à jour toutes vos statistiques. J'ai eu un problème très similaire et il s'est avéré que les statistiques sur une machine étaient bancales.

DForck42
la source
1

J'ai connu ce même comportement deux fois et je vais vous dire ce qui l'a corrigé à chaque fois:

1.) J'ai ajouté le conseil WITH RECOMPILE à la procédure stockée car le plan mis en cache était terrible.

2.) J'ai changé la procédure stockée pour utiliser des tables temporaires au lieu de variables de table.

J'espère que l'une ou l'autre de ces aides. Bonne chance.

Jon
la source