In mijn vorige post besprak ik LCK_M_XX, ASYNC_NETWORK_IO en OLEDB-wachten en de reflexmatige reacties daarop. In dit bericht ga ik verder met het thema wachtstatistieken en bespreek ik het wachten op SOS_SCHEDULER_YIELD.
Wanneer SOS_SCHEDULER_YIELD het meest voorkomt op een server, is het gebruikelijk om langdurig, hoog CPU-gebruik te zien. De reflexmatige reactie hier is dat de server onder CPU-druk moet staan, of dat een spinlock het probleem is.
We hebben hier wat achtergrondinformatie nodig om deze twee reacties te begrijpen.
Draadplanning
Thread-planning in SQL Server wordt beheerd door SQL Server zelf, niet door Windows (d.w.z. het is niet-preventief). Het SQL OS-gedeelte van de Storage Engine biedt planningsfunctionaliteit en de overgang van threads van draaien op een processor (waar de threadstatus RUNNING is) naar op de wachtlijst staan en wachten tot een resource beschikbaar komt (status is OPGESCHORT) naar runnable Wachtrij zodra de resource beschikbaar is (status is RUNNABLE) en wacht om bovenaan de wachtrij te komen en weer terug op de processor (terug naar de status RUNNING). Ik heb Processor, Waiter List en Runnable Queue met een hoofdletter geschreven om ze te identificeren als onderdelen van een planner.
Wanneer een thread een resource nodig heeft die niet onmiddellijk kan worden verkregen, wordt deze geschorst en wacht op de Waiter List om te horen (gesignaleerd) dat de resource beschikbaar is. De tijd die op de Waiter List wordt doorgebracht, is de wachttijd voor resources en de tijd die in de Runnable Queue wordt doorgebracht, is de wachttijd voor het signaal. Samen vormen ze de totale wachttijd. SQL OS houdt de wachttijd en de signaalwachttijd bij, dus we moeten wat rekenwerk doen op de uitvoer van sys.dm_os_wait_stats om de wachttijd van de resource af te leiden (zie mijn script hier).
De Waiter List is ongeordend (elke thread erop kan op elk moment worden gesignaleerd en naar de Runnable Queue worden verplaatst) en de Runnable Queue is bijna 100% van de tijd First-In-First-Out (FIFO). De enige uitzondering op de Runnable Queue die FIFO is, is waar meerdere Resource Governor-werkbelastinggroepen zijn geconfigureerd in dezelfde resourcepool en ze verschillende prioriteiten hebben ten opzichte van elkaar. Ik heb dit nog nooit met succes in productie gezien, dus ik zal het niet verder bespreken.
Er is nog een reden waarom een thread mogelijk van de processor moet worden verwijderd - het put zijn kwantum uit. Het threadquantum in SQL OS is vastgesteld op 4 milliseconden. De thread zelf is verantwoordelijk voor het bepalen dat zijn kwantum is uitgeput (door hulproutines aan te roepen in SQL OS) en voor het vrijwillig opgeven van de processor (bekend als yielding). Wanneer dit gebeurt, wordt de thread direct naar de onderkant van de Runnable Queue verplaatst, omdat er niets is om op te wachten. SQL OS moet echter een wachttype registreren voor deze overgang buiten de processor en registreert SOS_SCHEDULER_YIELD.
Dit gedrag wordt vaak aangezien voor CPU-druk, maar dat is het niet - het is gewoon aanhoudend CPU-gebruik. CPU-druk, en het herkennen ervan, is een heel ander onderwerp voor een toekomstig bericht. Wat dit bericht betreft, zolang de gemiddelde signaalwachttijd laag is (0-0,1-0,2 ms), is het een vrij veilige gok dat CPU-druk geen probleem is.
Spinlocks
Een spinlock is een primitief voor synchronisatie op zeer laag niveau die wordt gebruikt om thread-safe toegang te bieden tot gegevensstructuren in SQL Server die extreem heet zijn (zeer vluchtig en ongelooflijk vaak geopend en gewijzigd door meerdere threads). Voorbeelden van dergelijke structuren zijn de buffervrije lijst in elk deel van de bufferpool en de proportionele vullingswegingsreeks voor de gegevensbestanden in een bestandsgroep.
Wanneer een thread een spinlock moet krijgen, kijkt het of de spinlock vrij is en zo ja, verkrijgt het deze onmiddellijk (met behulp van een interlocked assembler primitief zoals 'test bit clear and set'). Als de spinlock niet kan worden verkregen, probeert de thread deze onmiddellijk opnieuw te verwerven, en opnieuw en opnieuw, tot duizend iteraties, totdat hij achteruitgaat (een tijdje slaapt). Dit wordt niet geregistreerd als een wachttype, omdat de thread gewoon de Windows-functie sleep() aanroept, maar andere threads die wachten, grote (10-20 ms+) signaalwachttijden kunnen geven, aangezien de slapende thread op de processor blijft totdat deze wordt krijgt de spinlock.
Waarom heb ik het over spinlocks? Omdat ze ook een oorzaak kunnen zijn van een hoog CPU-gebruik, en er is een misvatting dat spinlocks een oorzaak zijn van SOS_SCHEDULER_YIELD-wachten. Dat zijn ze niet.
SOS_SCHEDULER_YIELD Oorzaken
Er is dus één oorzaak voor SOS_SCHEDULER_YIELD:een thread die zijn planningsquantum uitput en zwaar terugkerende instanties kunnen ertoe leiden dat SOS_SCHEDULER_YIELD de meest voorkomende wachttijd is, samen met een hoog CPU-gebruik.
U zult SOS_SCHEDULER_YIELD-wachten niet zien verschijnen in de uitvoer van sys.dm_os_waiting_tasks, omdat de thread niet wacht. U kunt zien welke query de SOS_SCHEDULER_YIELD-wachttijden genereert door sys.dm_exec_requests op te vragen en te filteren op de kolom last_wait_type.
Dit betekent ook dat wanneer u SOS_SCHEDULER_YIELD in de uitvoer van sys.dm_os_wait_stats ziet, de resourcewacht nul zal zijn, omdat deze niet echt heeft gewacht. Maar onthoud dat elk van deze 'wachttijden' gelijk staat aan 4 ms CPU-tijd die is opgebouwd voor de zoekopdracht.
De enige manier om te bewijzen wat SOS_SCHEDULER_YIELD-wachten veroorzaakt, is door SQL Server-aanroepstacks vast te leggen wanneer dat wachttype optreedt, met behulp van Extended Events en foutopsporingssymbolen van Microsoft. Ik heb een blogpost die beschrijft en laat zien hoe dat onderzoek moet worden uitgevoerd, en er is een geweldige whitepaper over spinlocks en spinlock-onderzoeken die het lezen waard is als je geïnteresseerd bent in die diepte van internals.
In het geval van kwantumuitputting is dat niet de hoofdoorzaak. Het is een ander symptoom. Nu moeten we bedenken waarom een thread zijn kwantum herhaaldelijk kan uitputten.
Een thread kan zijn kwantum alleen uitputten als het 4 ms SQL Server-code kan blijven verwerken zonder een bron nodig te hebben die een andere thread bezit - niet wachten op vergrendelingen, paginavergrendelingen, gegevensbestandpagina's die van schijf moeten worden gelezen, geheugentoewijzingen, bestandsgroei, logboekregistratie , of de talloze andere bronnen die een thread nodig heeft.
Het meest voorkomende stuk code waarbij kwantumuitputting kan optreden en grote hoeveelheden SOS_SCHEDULER_YIELD-wachten kan veroorzaken, is het scannen van een index/tabel waar alle benodigde gegevensbestandenpagina's in het geheugen staan en er geen strijd is voor toegang tot die pagina's, en dat is dus wat Ik raad u aan om in queryplannen te zoeken wanneer u SOS_SCHEDULER_YIELD ziet als het hoogste wachttype:grote en/of herhaalde index-/tabelscans.
Dit betekent niet dat ik zeg dat grote scans slecht zijn, want het kan zijn dat de meest efficiënte manier om uw werklast te verwerken, een scan is. Als de SOS_SCHEDULER_YIELD-wachttijden echter nieuw en ongebruikelijk zijn en worden veroorzaakt door grote scans, moet u onderzoeken waarom de queryplannen gebruikmaken van scans. Misschien heeft iemand een kritieke niet-geclusterde index laten vallen, of zijn de statistieken verouderd en is er daarom een onjuist queryplan gekozen, of is er misschien een ongebruikelijke parameterwaarde doorgegeven aan een opgeslagen procedure en het queryplan vroeg om een scan of een codewijziging opgetreden zonder ondersteuning van indextoevoegingen.
Samenvatting
Net als bij andere soorten wacht, is het van cruciaal belang om te begrijpen wat SOS_SCHEDULER_YIELD precies betekent om te begrijpen hoe u het probleem kunt oplossen en of het gedrag wordt verwacht vanwege de werkbelasting die wordt verwerkt.
Wat algemene wachtstatistieken betreft, kunt u meer informatie vinden over het gebruik ervan voor het oplossen van problemen met de prestaties in:
- Mijn serie SQLskills-blogposts, te beginnen met Wachtstatistieken, of vertel me alsjeblieft waar het pijn doet
- Mijn bibliotheek met wachttypen en Latch-klassen hier
- Mijn online Pluralsight-trainingscursus SQL Server:prestatieproblemen oplossen met behulp van wachtstatistieken
- SQL Sentry Performance Advisor
In het volgende artikel in de serie zal ik een ander type wachten bespreken dat een veelvoorkomende oorzaak is van overhaaste reacties. Tot dan, veel plezier met het oplossen van problemen!