I mitt tidigare inlägg diskuterade jag LCK_M_XX, ASYNC_NETWORK_IO och OLEDB-väntningar och knä-rycks-reaktionerna på dem. I det här inlägget ska jag fortsätta med temat väntestatistik och diskutera SOS_SCHEDULER_YIELD-väntan.
När SOS_SCHEDULER_YIELD är den vanligaste på en server, är det vanligt att se ihållande, hög CPU-användning. Reaktionen här är att servern måste vara under CPU-tryck, eller att ett spinlock är problemet.
Vi behöver lite bakgrund här för att förstå dessa två reaktioner.
Trådschemaläggning
Trådschemaläggning i SQL Server hanteras av SQL Server själv, inte av Windows (dvs. det är icke-förebyggande). SQL OS-delen av Storage Engine tillhandahåller schemaläggningsfunktioner och trådar övergår från att köras på en processor (där trådtillståndet KÖR) till att vara på servitörslistan och väntar på att en resurs ska bli tillgänglig (tillståndet är AVSTÄNGD) till att vara på den körbara Ställ i kö när resursen blir tillgänglig (tillståndet är KÖRBAR) och väntar på att komma till toppen av kön och tillbaka till processorn igen (tillbaka till tillståndet KÖR). Jag har skrivit processor, servitörslista och körbar kö för att identifiera dem som delar av en schemaläggare.
Närhelst en tråd behöver en resurs som den inte omedelbart kan skaffa, stängs den av och väntar på servitörslistan för att få veta (signaleras) att dess resurs är tillgänglig. Den tid som spenderas på servitörslistan är resursväntetiden och tiden som spenderas på den körbara kön är signalväntetiden. Tillsammans utgör de den totala väntetiden. SQL OS håller reda på väntetiden och signalväntetiden så vi måste göra lite matte på utdata från sys.dm_os_wait_stats för att härleda resursväntetiden (se mitt skript här).
Servitörslistan är oordnad (vilken tråd som helst på den kan signaleras när som helst och flyttas till den körbara kön) och den körbara kön är först-in-först-ut (FIFO) nästan 100 % av tiden. Det enda undantaget från den körbara kön är FIFO där flera arbetsbelastningsgrupper för resursguvernör har konfigurerats i samma resurspool och de har olika prioriteringar i förhållande till varandra. Jag har aldrig sett detta användas framgångsrikt i produktionen så jag kommer inte att diskutera det mer.
Det finns en annan anledning till att en tråd kan behöva flyttas från processorn – den tar slut. Trådkvantumet i SQL OS är fixerat till 4 millisekunder. Tråden själv är ansvarig för att fastställa att dess kvantum har uttömts (genom att anropa hjälprutiner i SQL OS) och frivilligt ge upp processorn (känd som ger). När detta inträffar flyttas tråden direkt till botten av den körbara kön, eftersom det inte finns något att vänta på. SQL OS måste dock registrera en väntetyp för denna övergång från processorn och registrerar SOS_SCHEDULER_YIELD.
Detta beteende misstas ofta för CPU-tryck, men det är det inte – det är bara ihållande CPU-användning. CPU-tryck, och att känna igen det, är ett helt annat ämne för ett framtida inlägg. När det gäller detta inlägg, så länge som den genomsnittliga signalväntetiden är låg (0-0,1-0,2 ms), är det ett ganska säkert kort att CPU-trycket inte är ett problem.
Spinlocks
Ett spinlock är en primitiv för synkronisering på mycket låg nivå som används för att ge trådsäker åtkomst till datastrukturer i SQL Server som är extremt heta (mycket flyktiga och åtkomliga och ändras otroligt ofta av flera trådar). Exempel på sådana strukturer är buffertfri lista i varje del av buffertpoolen och viktningsmatrisen för proportionell fyllning för datafilerna i en filgrupp.
När en tråd behöver skaffa ett spinlock, ser den ut om spinlocket är ledigt och om så är fallet förvärvar det omedelbart (med hjälp av en sammankopplad assembly-språk primitiv som "test bit clear and set"). Om spinlocket inte kan erhållas, försöker tråden omedelbart förvärva det igen, och igen, och igen, i upp till tusen iterationer, tills den backar (sover en stund). Detta registreras inte som någon väntetyp, eftersom tråden helt enkelt anropar Windows sleep()-funktionen, men kan göra att andra trådar som väntar har långa (10-20ms+) signalväntetider eftersom den sovande tråden stannar på processorn tills den får spinlocket.
Varför pratar jag om spinlocks? Eftersom de också kan vara en orsak till hög CPU-användning, och det finns en missuppfattning att spinlocks är en orsak till SOS_SCHEDULER_YIELD-väntningar. Det är de inte.
SOS_SCHEDULER_YIELD Orsaker
Så det finns en orsak till SOS_SCHEDULER_YIELD:en tråd som tar ut sin schemaläggningskvantum och kraftigt återkommande instanser kan leda till att SOS_SCHEDULER_YIELD är den vanligaste väntan tillsammans med hög CPU-användning.
Du kommer inte att se SOS_SCHEDULER_YIELD-väntningar dyka upp i utdata från sys.dm_os_waiting_tasks, eftersom tråden inte väntar. Du kan se vilken fråga som genererar SOS_SCHEDULER_YIELD-väntningarna genom att fråga sys.dm_exec_requests och filtrera i kolumnen last_wait_type.
Detta betyder också att när du ser SOS_SCHEDULER_YIELD i utdata från sys.dm_os_wait_stats, kommer resursväntningen att vara noll, eftersom den faktiskt inte väntade. Men kom ihåg att var och en av dessa "väntningar" motsvarar 4 ms CPU-tid som samlats in för frågan.
Det enda sättet att bevisa vad som orsakar SOS_SCHEDULER_YIELD väntar är att fånga SQL Server-anropsstackar när den väntetypen inträffar, med hjälp av utökade händelser och felsökningssymboler från Microsoft. Jag har ett blogginlägg som beskriver och visar hur man utför den undersökningen, och det finns ett bra whitepaper om spinlocks och spinlock-undersökningar som är värt att läsa om du är intresserad av det djupet av interna detaljer.
För fallet med kvantutmattning är det inte grundorsaken. Det är ytterligare ett symptom. Nu måste vi överväga varför en tråd kan uttömma sitt kvantum upprepade gånger.
En tråd kan bara tömma sitt kvantum när den kan fortsätta bearbeta SQL Server-kod i 4ms utan att behöva en resurs som en annan tråd äger – ingen väntan på lås, sidlås, datafilsidor som ska läsas från disk, minnesallokering, filtillväxt, loggning , eller de otaliga andra resurser som en tråd kan behöva.
Den vanligaste kodbiten där kvantutmattning kan uppstå och samla på sig stora mängder SOS_SCHEDULER_YIELD-väntningar är att skanna ett index/tabell där alla nödvändiga datafilsidor finns i minnet och det inte finns något tvivel om åtkomst till dessa sidor, och så det är vad Jag uppmuntrar dig att leta efter i frågeplaner när du ser SOS_SCHEDULER_YIELD som den bästa väntetypen – stora och/eller upprepade index-/tabellsökningar.
Detta betyder inte att jag säger att stora skanningar är dåliga, eftersom det kan vara så att det mest effektiva sättet att bearbeta din arbetsbelastning är genom en skanning. Men om SOS_SCHEDULER_YIELD-väntningarna är nya och ovanliga och orsakas av stora skanningar, bör du undersöka varför sökplanerna använder skanningar. Kanske har någon tappat ett kritiskt icke-klustrat index, eller så är statistiken inaktuell och så valdes en felaktig frågeplan, eller så skickades ett ovanligt parametervärde till en lagrad procedur och frågeplanen krävde en skanning eller en kodändring skedde utan stödjande indextillägg.
Sammanfattning
Precis som med andra väntetyper är det viktigt att förstå exakt vad SOS_SCHEDULER_YIELD betyder för att förstå hur man felsöker det och om beteendet förväntas på grund av arbetsbelastningen som bearbetas.
När det gäller allmän väntestatistik kan du hitta mer information om hur du använder dem för prestandafelsökning i:
- Min SQLskills blogginläggsserie, som börjar med Vänta statistik, eller snälla berätta för mig var det gör ont
- Mina väntetyper och låsklasser-bibliotek här
- Min Pluralsight onlinekurs SQL Server:Prestandafelsökning med hjälp av väntastatistik
- SQL Sentry Performance Advisor
I nästa artikel i serien kommer jag att diskutera en annan väntetyp som är en vanlig orsak till knä-ryck-reaktioner. Tills dess, glad felsökning!