Les instructions SQL Server ralentissent par intermittence sur SQL Server 2008 R2


13

Sur l'un de nos clients, nous avons eu des problèmes de performances sur notre application. Il s'agit d'une application Web .NET 3.5 qui consomme et met à jour des données sur une base de données SQL Server. Actuellement, notre environnement de production se compose d'une machine Windows 2008 R2 comme frontal et d'un cluster SQL Server 2008 R2 à l'arrière. Notre application utilise COM + et MSDTC pour se connecter à la base de données.

Voici ce qui se passe: nos utilisateurs finaux se plaignent parfois de lenteur dans l'application. Certaines pages prennent plus de temps à charger que prévu. Tout en essayant de comprendre ce qui se passe, j'ai réussi à découvrir un comportement étrange du côté de la base de données qui peut être la cause de la dégradation des performances. J'ai remarqué que parfois il y a des instructions SQL qui prennent beaucoup plus de temps à exécuter que ce qui serait attendu. J'ai réussi à identifier certaines de ces instructions (principalement des invocations de certaines des procédures stockées de notre application) à l'aide d'une trace de profileur (avec le modèle TSQL_Duration) pour identifier les requêtes de longue durée.

Le problème est que lorsque j'exécute ces procédures stockées directement sur la base de données sur SQL Management Studio, elles prennent parfois longtemps (environ 7/8 secondes), d'autres fois elles sont rapides (moins de 1 seconde). Je ne sais pas pourquoi cela se produit et cela me rend fou, car la machine SQL (4 cœurs, 32 Go) n'est utilisée par aucune autre application, et ces requêtes ne devraient pas prendre autant de temps à s'exécuter.

N'étant pas un DBA ou un gourou de SQL Server, j'ai essayé de regarder quelques trucs qui pourraient m'aider à comprendre le problème. Voici les étapes que j'ai prises pour essayer de résoudre le problème et ce que j'ai découvert jusqu'à présent:

  • Tout le code TSQL appelé par l'application est écrit dans des procédures stockées.
  • J'ai identifié certaines des requêtes de longue durée sur le profileur SQL Server, mais lorsque je les exécute sur Management Studio, elles prennent beaucoup de temps (de 4 à 10 secondes) ou s'exécutent rapidement (moins de 1 seconde). J'exécute exactement les mêmes requêtes avec les mêmes données transmises dans les paramètres. Ces requêtes sont principalement des procédures stockées contenant des instructions select.
  • J'ai essayé de regarder les statistiques des attentes et des files d'attente pour essayer de déterminer s'il y a des processus en attente sur certaines ressources. J'ai exécuté la requête suivante:

WITH Waits AS
    (SELECT
        wait_type,
        wait_time_ms / 1000.0 AS WaitS,
        (wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS,
        signal_wait_time_ms / 1000.0 AS SignalS,
        waiting_tasks_count AS WaitCount,
        100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS Percentage,
        ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS RowNum
    FROM sys.dm_os_wait_stats
    WHERE wait_type NOT IN (
        'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
        'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
        'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',  'BROKER_TO_FLUSH',
        'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT',     'DISPATCHER_QUEUE_SEMAPHORE',
        'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
        'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
        'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
        'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
        'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
    )
SELECT
    W1.wait_type AS WaitType, 
    CAST (W1.WaitS AS DECIMAL(14, 2)) AS Wait_S,
    CAST (W1.ResourceS AS DECIMAL(14, 2)) AS Resource_S,
    CAST (W1.SignalS AS DECIMAL(14, 2)) AS Signal_S,
    W1.WaitCount AS WaitCount,
    CAST (W1.Percentage AS DECIMAL(4, 2)) AS Percentage,
    CAST ((W1.WaitS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgWait_S,
    CAST ((W1.ResourceS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgRes_S,
    CAST ((W1.SignalS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgSig_S
FROM Waits AS W1
    INNER JOIN Waits AS W2 ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type, W1.WaitS, W1.ResourceS, W1.SignalS, W1.WaitCount,    W1.Percentage
HAVING SUM (W2.Percentage) - W1.Percentage < 95; -- percentage threshold
GO

Voici ce que j'ai découvert:

  • Après avoir réinitialisé les statistiques à l'aide de DBCC SQLPERF (environ 1 ou 2 heures après), les types d'attente que j'ai le plus sont SOS_SCHEDULER_YIELD et WRITELOG
  • Au fil du temps (après environ 1 jour d'exécution), les types d'attente les plus fréquents dans la base de données sont CXPACKET (67%) et OLEDB (17%), même si le temps d'attente moyen pour chacun n'est pas long. J'ai également remarqué que les instructions les plus longues identifiées sur SQL Profiler sont des appels à des procédures stockées qui retournent plus d'un jeu de résultats (souvent 3). Peut-il y avoir un problème de paralellisme ici? Existe-t-il un moyen d’essayer d’identifier si c’est la cause du problème?
  • J'ai lu quelque part que les attentes OLEDB peuvent être causées par des appels aux ressources OLEDB comme les serveurs liés. Nous avons un serveur lié pour se connecter à une machine des services d'indexation (MSIDXS), mais aucune des déclarations identifiées comme étant en cours d'exécution n'utilise ce serveur lié.
  • Le temps d'attente moyen le plus élevé dont je dispose concerne les attentes de type LCK_M_X (environ 1,5 seconde en moyenne), mais ces types d'attente ne se produisent pas très souvent par rapport à d'autres types (par exemple, 64 attentes LCK_M_X contre 10 823 CXPACKET attendent sur la même période) ).
  • Une chose que j'ai remarquée est que le service MSDTC n'est pas en cluster. Le service SQL Server est en cluster mais pas MSDTC. Peut-il y avoir un impact sur les performances à cause de cela? Nous utilisons MSDTC parce que notre application utilise Enterprise Services (DCOM) pour accéder à la base de données, mais les serveurs n'ont pas été installés et configurés par nous, mais par notre client.

Quelqu'un peut-il m'aider à mieux comprendre ces données? Quelqu'un peut-il m'aider à comprendre ce qui peut arriver? Puis-je faire quelque chose sur le serveur pour essayer de comprendre les choses? Dois-je parler à l'équipe de développement d'applications?

Réponses:


4

Merci pour l'explication détaillée de votre problème (l'une des questions les mieux posées en fait).

WRITELOG est un type d'attente très courant, alors ne vous en faites pas. En regardant le SOS_SCHEDULER_YIELD indiquer la pression du processeur et aussi le CXPACKET, il est possible qu'il doit y avoir des index manquants et vous pouvez récupérer beaucoup de données des requêtes pour un système OLTP. Je vous suggère de regarder le DMV des index manquants et de voir s'il y a des index (presque sûrs qu'il y en aura plus que quelques-uns) qui sont dans les procs douteux.

http://sqlfool.com/2009/04/a-look-at-missing-indexes/

http://troubleshootingsql.com/2009/12/30/how-to-find-out-the-missing-indexes-on-a-sql-server-2008-or-2005-instance-along-with-the- créer-index-commandes /

Recherchez également la publication de Jonathan Kehayias sur sqlblog.com.

Jetez également un œil au reniflage des paramètres.

http://sommarskog.se/query-plan-mysteries.html

http://pratchev.blogspot.com/2007/08/parameter-sniffing.html

Ce n'est PAS une réponse compétitive à vos besoins mais un bon point de départ. Faites-nous savoir si vous avez besoin de plus de détails.


1

Nous avons eu un problème similaire après qu'un des employés a réécrit quelques-unes des procédures stockées. Il s'est avéré qu'il y avait une ramification excessive et Dynamic SQL en cours de construction qui a modifié la clause where de manière significative.

Par exemple (simplifié bien sûr):

Si le modèle était "X", la clause where recherchée pour ProductCode est égale à certaines valeurs.
Si le modèle était "Y", la clause where recherchait ProductType égal à certaines valeurs.

SQL Server créera un plan de requête basé sur les paramètres d'entrée lors de la première exécution de la procédure stockée. Donc, si le plan de requête est construit sur une logique qui utilise "ProductCode" est égal à et que vous demandez "ProductType" est égal à c'est un plan de requête non apparié et se traduit très probablement par une analyse complète de la table.

Vous pouvez essayer de placer " AVEC RECOMPILE " en haut de la procédure stockée. CRÉER UNE PROCÉDURE (Transact-SQL)

La meilleure façon de décrire cela est la suivante:

Supposons que vous ayez une liste de noms et de numéros de téléphone triés par nom de famille. Cela fonctionne très bien pour trouver des personnes en utilisant leur nom de famille (plan de requête basé sur le nom de famille). Supposons maintenant que vous ayez besoin de tous les noms et numéros de téléphone de l'indicatif régional 203. Si votre liste est triée par nom de famille, la seule façon d'obtenir une liste complète de toutes les personnes de l'indicatif régional 203 est de commencer par le haut et de lire séquentiellement chacun et chaque enregistrement. (Analyse complète de la table).


L'utilisation de la exec()fonction expliquerait le comportement observé. Dans ce cas, l'utilisation sp_executesqlrésout normalement les problèmes liés aux instructions SQL dynamiques.
ajeh

1

Si les requêtes s'exécutent par intermittence, rapidement et lentement dans SSMS et l'application, vous pouvez avoir un problème de reniflement des statistiques ou des paramètres.

J'exécuterais ces procédures stockées, puis examinerais le plan d'exécution pour extraire les propriétés de l'opérateur racine (nœud vert à l'extrême gauche de chaque instruction).

Quel est le nombre estimé de lignes dans le plan d'exécution, par rapport au nombre de lignes réelles qui ont été renvoyées?

Le paramètre compilé correspond-il au paramètre de requête réel?

Si le plan d'exécution a été créé pour un paramètre qui ne renvoie qu'une poignée de lignes et que vous exécutez la même procédure avec un paramètre qui renvoie un grand nombre de lignes, SQL peut utiliser le plan d'exécution incorrect pour la requête.

Les choix de plan d'exécution sont étroitement liés aux statistiques SQL, c'est donc une bonne idée de reconstruire vos statistiques régulièrement.

Si vous avez une procédure stockée qui renvoie parfois de petites quantités de données ou de grandes quantités de données en fonction du paramètre fourni, vous pouvez avoir un problème de reniflement de paramètre.

Si la reconstruction de vos statistiques ne résout pas le problème, vous pouvez exécuter les instructions les plus coûteuses dans la procédure stockée avec OPTION (RECOMPILE)


0

Comme vous avez identifié des requêtes de longue durée, vous pouvez récupérer les plans d'exécution de ces procédures dans votre cache et voir si vous pouvez y déterminer le problème. Il existe souvent des conversions implicites ou au moment de l'exécution des types de données. De plus, si vous purgez ou insérez beaucoup de données, il est également conseillé de mettre à jour les statistiques.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.