Database
 sql >> Base de données >  >> RDS >> Database

Statistiques d'attente instinctives :SOS_SCHEDULER_YIELD

Dans mon article précédent, j'ai discuté des attentes LCK_M_XX, ASYNC_NETWORK_IO et OLEDB et des réactions instinctives à celles-ci. Dans cet article, je vais continuer avec le thème des statistiques d'attente et discuter de l'attente SOS_SCHEDULER_YIELD.

Lorsque SOS_SCHEDULER_YIELD est le plus répandu sur un serveur, il est courant de voir une utilisation soutenue et élevée du processeur. La réaction instinctive ici est que le serveur doit être sous pression CPU, ou qu'un spinlock est le problème.

Nous avons besoin d'un peu de contexte ici pour comprendre ces deux réactions.

Planification des threads

La planification des threads dans SQL Server est gérée par SQL Server lui-même, et non par Windows (c'est-à-dire qu'elle n'est pas préemptive). La partie SQL OS du moteur de stockage fournit la fonctionnalité de planification et la transition des threads de l'exécution sur un processeur (où l'état du thread est EN COURS D'EXÉCUTION) à l'inscription sur la liste d'attente en attendant qu'une ressource devienne disponible (l'état est SUSPENDU) à l'exécution sur le Runnable File d'attente une fois que la ressource devient disponible (l'état est RUNNABLE) en attendant d'arriver en haut de la file d'attente et de revenir sur le processeur (retour à l'état étant RUNNING). J'ai mis en majuscule Processor, Waiter List et Runnable Queue pour les identifier comme faisant partie d'un planificateur.

Chaque fois qu'un thread a besoin d'une ressource qu'il ne peut pas acquérir immédiatement, il est suspendu et attend sur la liste d'attente d'être informé (signalé) que sa ressource est disponible. Le temps passé sur la liste d'attente est le temps d'attente des ressources et le temps passé sur la file d'attente exécutable est le temps d'attente du signal. Ensemble, ils se combinent pour former le temps d'attente global. SQL OS garde une trace du temps d'attente et du temps d'attente du signal, nous devons donc faire quelques calculs sur la sortie de sys.dm_os_wait_stats pour dériver le temps d'attente des ressources (voir mon script ici).

La liste d'attente n'est pas ordonnée (tout thread qui s'y trouve peut être signalé à tout moment et passer à la file d'attente exécutable) et la file d'attente exécutable est le premier entré, premier sorti (FIFO) presque 100 % du temps. La seule exception à la file d'attente exécutable étant FIFO est lorsque plusieurs groupes de charge de travail du gouverneur de ressources ont été configurés dans le même pool de ressources et qu'ils ont des priorités différentes les uns par rapport aux autres. Je n'ai jamais vu cela utilisé avec succès dans la production, donc je n'en parlerai pas davantage.

Il y a une autre raison pour laquelle un thread peut avoir besoin de quitter le processeur - il épuise son quantum. Le quantum de thread dans SQL OS est fixé à 4 millisecondes. Le thread lui-même est chargé de déterminer que son quantum a été épuisé (en appelant des routines d'assistance dans SQL OS) et d'abandonner volontairement le processeur (appelé rendement). Lorsque cela se produit, le thread se déplace directement au bas de la file d'attente exécutable, car il n'y a rien à attendre. SQL OS doit cependant enregistrer un type d'attente pour cette transition hors du processeur et enregistre SOS_SCHEDULER_YIELD.

Ce comportement est souvent confondu avec la pression du processeur, mais ce n'est pas le cas - c'est juste une utilisation soutenue du processeur. La pression du processeur, et sa reconnaissance, est un tout autre sujet pour un futur article. En ce qui concerne cet article, tant que le temps d'attente moyen du signal est faible (0-0,1-0,2 ms), il y a fort à parier que la pression du processeur n'est pas un problème.

Spinlocks

Un spinlock est une primitive de synchronisation de très bas niveau qui est utilisée pour fournir un accès thread-safe aux structures de données dans SQL Server qui sont extrêmement chaudes (très volatiles et consultées et modifiées incroyablement fréquemment par plusieurs threads). Des exemples de telles structures sont la liste de tampons libres dans chaque partie du pool de tampons et le tableau de pondérations de remplissage proportionnel pour les fichiers de données dans un groupe de fichiers.

Lorsqu'un thread a besoin d'acquérir un verrou tournant, il regarde si le verrou tournant est libre et, si c'est le cas, l'acquiert immédiatement (en utilisant une primitive de langage d'assemblage verrouillée comme "test bit clear and set"). Si le verrou tournant ne peut pas être acquis, le thread essaie immédiatement de l'acquérir à nouveau, et encore, et encore, jusqu'à un millier d'itérations, jusqu'à ce qu'il recule (dort un peu). Cela ne s'enregistre pas comme un type d'attente, car le thread appelle simplement la fonction Windows sleep (), mais peut faire en sorte que d'autres threads en attente aient des temps d'attente de signal importants (10-20 ms +) car le thread en veille reste sur le processeur jusqu'à ce qu'il obtient le verrou tournant.

Pourquoi est-ce que je parle de spinlocks ? Parce qu'ils peuvent également être une cause d'utilisation élevée du processeur, et il y a une idée fausse selon laquelle les spinlocks sont une cause des attentes SOS_SCHEDULER_YIELD. Ils ne le sont pas.

Causes SOS_SCHEDULER_YIELD

Il y a donc une cause à SOS_SCHEDULER_YIELD :un thread épuisant son quantum de planification et des instances fortement récurrentes peuvent faire en sorte que SOS_SCHEDULER_YIELD soit l'attente la plus répandue avec une utilisation élevée du processeur.

Vous ne verrez pas les attentes SOS_SCHEDULER_YIELD apparaître dans la sortie de sys.dm_os_waiting_tasks, car le thread n'attend pas. Vous pouvez voir quelle requête génère les attentes SOS_SCHEDULER_YIELD en interrogeant sys.dm_exec_requests et en filtrant sur la colonne last_wait_type.

Cela signifie également que lorsque vous voyez SOS_SCHEDULER_YIELD dans la sortie de sys.dm_os_wait_stats, l'attente de la ressource sera nulle, car elle n'a pas réellement attendu. Mais rappelez-vous que chacune de ces "attentes" équivaut à 4 ms de temps CPU accumulés pour la requête.

Le seul moyen de prouver la cause des attentes SOS_SCHEDULER_YIELD consiste à capturer les piles d'appels SQL Server lorsque ce type d'attente se produit, à l'aide d'événements étendus et de symboles de débogage de Microsoft. J'ai un article de blog qui décrit et montre comment effectuer cette enquête, et il y a un excellent livre blanc sur les spinlocks et les enquêtes sur les spinlocks qui vaut la peine d'être lu si vous êtes intéressé par cette profondeur d'internes.

Dans le cas de l'épuisement quantique, ce n'est pas la cause première. C'est un autre symptôme. Nous devons maintenant examiner pourquoi un thread peut épuiser son quantum à plusieurs reprises.

Un thread ne peut épuiser son quantum que lorsqu'il peut continuer à traiter le code SQL Server pendant 4 ms sans avoir besoin d'une ressource appartenant à un autre thread - pas d'attente pour les verrous, les verrous de page, les pages de fichiers de données à lire à partir du disque, les allocations de mémoire, les croissances de fichiers, la journalisation , ou la myriade d'autres ressources dont un thread peut avoir besoin.

Le morceau de code le plus courant où l'épuisement quantique peut se produire et accumuler de grandes quantités d'attentes SOS_SCHEDULER_YIELD est l'analyse d'un index/table où toutes les pages de fichiers de données nécessaires sont en mémoire et il n'y a pas de conflit pour accéder à ces pages, et donc c'est ce que Je vous encourage à rechercher dans les plans de requête lorsque vous voyez SOS_SCHEDULER_YIELD comme le type d'attente le plus élevé - analyses d'index/tables volumineuses et/ou répétées.

Cela ne signifie pas que je dis que les analyses volumineuses sont mauvaises, car il se pourrait que le moyen le plus efficace de traiter votre charge de travail consiste à effectuer une analyse. Toutefois, si les attentes SOS_SCHEDULER_YIELD sont nouvelles et inhabituelles, et sont causées par de grandes analyses, vous devez rechercher pourquoi les plans de requête utilisent des analyses. Peut-être que quelqu'un a supprimé un index critique non clusterisé, ou que les statistiques sont obsolètes et qu'un plan de requête incorrect a donc été choisi, ou peut-être qu'une valeur de paramètre inhabituelle a été transmise à une procédure stockée et que le plan de requête a appelé pour une analyse ou un changement de code s'est produit sans prendre en charge les ajouts d'index.

Résumé

Comme pour les autres types d'attente, comprendre exactement ce que signifie SOS_SCHEDULER_YIELD est essentiel pour comprendre comment le résoudre et si le comportement est attendu en raison de la charge de travail en cours de traitement.

En ce qui concerne les statistiques d'attente générales, vous pouvez trouver plus d'informations sur leur utilisation pour le dépannage des performances dans :

  • Ma série d'articles de blog SQLskills, en commençant par les statistiques d'attente, ou s'il vous plaît dites-moi où ça fait mal
  • Bibliothèque de mes types d'attente et de mes classes de verrouillage ici
  • Ma formation en ligne Pluralsight SQL Server :Dépannage des performances à l'aide des statistiques d'attente
  • Conseiller de performances SQL Sentry

Dans le prochain article de la série, je discuterai d'un autre type d'attente qui est une cause fréquente de réactions instinctives. En attendant, bon dépannage !