2010-08-25 7 views
5

Je développe un système qui périodiquement (4-5 fois par jour) exécute une instruction select, qui prend normalement moins de 10 secondes mais qui a duré jusqu'à 40 minutes.Requête lente intermittente sur SQL Server 2008

La base de données est sur Windows Server 2008 + SQL Server 2008 R2; les deux 64bit.

Il existe un service sur la machine exécutant la base de données qui interroge la base de données et génère des valeurs pour les enregistrements qui en ont besoin. Ces enregistrements sont ensuite périodiquement interrogés à l'aide d'une sélection de jointure multi-tables à partir d'un service sur une deuxième machine écrite en C++ (VS 2010) à l'aide de la classe MFC CRecordset pour extraire les données. Un exemple de la requête à l'origine du problème est illustré ci-dessous.

SELECT DISTINCT "JobKeysFrom"."Key" AS "KeyFrom","KeysFrom"."ID" AS "IDFrom", 
"KeysFrom"."X" AS "XFrom","KeysFrom"."Y" AS "YFrom","JobKeysTo"."Key" AS "KeyTo", 
"KeysTo"."ID" AS "IDTo","KeysTo"."X" AS "XTo","KeysTo"."Y" AS "YTo", 
"Matrix"."TimeInSeconds","Matrix"."DistanceInMetres","Matrix"."Calculated" 
FROM "JobKeys" AS "JobKeysFrom" 
INNER JOIN "JobKeys" AS "JobKeysTo" ON 
("JobKeysFrom"."Key"<>"JobKeysTo"."Key") AND 
("JobKeysFrom"."JobID"=531) AND 
("JobKeysTo"."JobID"=531) 
INNER JOIN "Keys" AS "KeysFrom" ON 
("JobKeysFrom"."Key"="KeysFrom"."Key") AND ("JobKeysFrom"."Status"=4) 
INNER JOIN "Keys" AS "KeysTo" ON 
("JobKeysTo"."Key"="KeysTo"."Key") AND ("JobKeysTo"."Status"=4) 
INNER JOIN "Matrix" AS "Matrix" ON 
("Matrix"."IDFrom"="KeysFrom"."ID") AND ("Matrix"."IDTo"="KeysTo"."ID") 
ORDER BY "JobKeysFrom"."Key","JobKeysTo"."Key" 

J'ai essayé ce qui suit

  1. vérifié les indices et tous semblent corrects et ils sont actifs et sont utilisés conformément à la requête
  2. le conseiller en conception revient sans suggestions
  3. J'ai essayé de défragmenter les index et les données
  4. reconstruit la base de données à partir de zéro en exportant les données et en les réimportant dans une nouvelle base de données.
  5. a exécuté le profileur sur elle et a constaté que quand il va mal, il semble faire plusieurs millions (jusqu'à 100 millions) de lectures plutôt que de quelques centaines de milliers.
  6. couru la base de données sur un autre serveur

Pendant le temps est en cours d'exécution de la requête, je peux courir exactement la même requête dans la fenêtre du studio de gestion et il sera de retour à la course en 10 secondes. Le problème ne semble pas être lié au verrou, à l'interblocage, au processeur, au disque ou à la mémoire, comme il l'a fait lorsque la machine exécutant la base de données n'exécutait qu'une seule requête. Le serveur a 4 processeurs et 16 Go de mémoire pour l'exécuter. J'ai également essayé de mettre à jour les disques à des plus rapides et cela n'a eu aucun effet.

Il me semble que c'est presque comme si la base de données recevait la requête, commençait à la traiter et puis se met en veille pendant 40 minutes ou exécute la requête sans utiliser les index.

Lorsque cela prend du temps, il finit par finir et envoie les résultats de la requête (normalement environ 70-100000 enregistrements) à l'application appelante.

Toute aide ou suggestions reçus avec reconnaissance, merci beaucoup

+0

Cette requête est-elle exécutée en tant que procédure stockée paramétrée? –

+0

Pouvez-vous éviter le SELECT DISTINCT? Cela peut nuire gravement à la performance. –

+1

@Yves: semble assez performant pour fonctionner ad hoc, et revient en 10 secondes. –

Répondre

3

Cela ressemble beaucoup à renifler des paramètres. Lorsqu'une procédure stockée est invoquée et qu'aucun plan d'exécution existant dans le cache ne correspond aux options set pour la connexion, un nouveau plan d'exécution est compilé à l'aide des valeurs de paramètre transmises lors de cet appel. Parfois, cela se produit lorsque les paramètres transmis sont atypiques (par exemple, ont une sélectivité inhabituellement élevée), de sorte que le plan généré ne sera pas adapté à la plupart des autres invocations avec des paramètres différents. Par exemple, il peut choisir un plan avec des recherches d'index et des recherches de signets, ce qui est bien pour un cas très sélectif mais médiocre si cela doit être fait des centaines de milliers de fois.

Ceci expliquerait pourquoi le nombre de lectures passe par le toit.

Votre connexion SSMS aura probablement différentes SET ... options afin ne sera pas remis le même plan de problème à partir du cache lorsque vous exécutez la procédure stockée à l'intérieur SSMS

Vous pouvez utiliser ce qui suit pour obtenir le plan de la session lente

select p.query_plan, * 
from sys.dm_exec_requests r 
cross apply sys.dm_exec_query_plan(r.plan_handle) p 
where r.session_id = <session_id> 

Alors comparer avec le plan de la bonne session.

Si vous déterminez que le reniflage des paramètres est en cause, vous pouvez utiliser les indicateurs OPTIMIZE FOR pour éviter de choisir le mauvais plan.

+0

Je pense que nous construisons nos discours sur les conditions initiales invalides et les déclarations :) – garik

0

Vérifiez qu'aucune tâche de maintenance n'est en cours de reconstruction des index ou que les statistiques de votre base de données ne sont pas valides lors de l'exécution de la requête. C'est exactement le genre de chose que l'on pourrait s'attendre à voir si la requête n'utilise pas vos index, généralement parce que les index ne sont pas accessibles à la requête au moment où elle s'exécute ou parce que les statistiques sont invalides et faites croire à l'optimiseur que votre ou vos grandes tables ne contiennent que quelques lignes et que la requête s'exécuterait plus rapidement avec un balayage de table complet qu'avec un accès indexé.

+0

Vous avez manqué le point qu'une exécution simultanée de la même requête retourne rapidement? –

Questions connexes