Introduktion
SQL Server-frågeoptimeraren använder sig av statistik under frågekompileringen för att hjälpa till att bestämma den optimala frågeplanen. Som standard, om optimeraren märker att en statistik är inaktuell på grund av för många ändringar i en tabell, kommer den att uppdatera statistiken omedelbart innan frågekompileringen kan fortsätta (endast den statistik den behöver, inte all statistik för tabellen) .
Observera att "för många" är ospecifikt eftersom det varierar beroende på version och om spårningsflagga 2371 är aktiverad – se avsnittet AUTO_UPDATE_STATISTICS på denna sida för detaljer.
Problemet med synkrona statistikuppdateringar
Synkron uppdatering av statistik före kompilering introducerar uppenbarligen en fördröjning och gör att frågan tar längre tid att kompilera och köra. Hur stor förseningen är beror på flera faktorer, inklusive:
- Hur många tabeller som är involverade i frågan har nått tröskeln för "för många ändringar"
- Hur mycket statistik för var och en av dessa tabeller måste uppdateras eftersom de behövs för sammanställning
- Hur många rader det finns i de inblandade tabellerna
- Alternativen som angavs när varje statistik skapades (t.ex. FULLSCAN och PERSIST_SAMPLE_PERCENT=ON)
Så det kan förekomma en till synes slumpmässig fördröjning, vilket kan orsaka problem i vissa scenarier, särskilt om en applikation har en mycket låg tidsgräns för sökfrågan.
Undvika synkrona statistikuppdateringar
Det finns olika sätt att undvika synkrona statistikuppdateringar, till exempel:
- Att ställa in AUTO_UPDATE_STATISTICS på AV, vilket stänger av alla automatiska uppdateringar och innebär att du måste utföra ditt eget statistikunderhåll för att undvika möjligheten till suboptimala frågeplaner från inaktuell statistik.
- Inställning av AUTO_UPDATE_STATISTICS_ASYNC till PÅ, så när optimeraren märker att en statistik behöver uppdateras, fortsätter den med kompileringen och en bakgrundsuppgift uppdaterar statistiken lite senare. Detta fungerar bara om du också har AUTO_UPDATE_STATISTICS inställt på PÅ.
- Utför regelbundet statistikunderhåll, så att automatiska synkrona eller asynkrona statistikuppdateringar inte sker alls.
Det finns en hel del debatt i SQL Server-gemenskapen om huruvida asynkrona statistikuppdateringar ska aktiveras. Jag frågade min underbara fru, Kimberly L. Tripp, vad hennes åsikt är, och hon rekommenderar alltid att aktivera det, och hon har glömt mer om statistik än jag någonsin kommer att veta, så jag tror på henne. ☺
Spåra synkrona statistikuppdateringar
Det har aldrig funnits ett självklart sätt att avgöra om en fråga tog lång tid eftersom den väntade på en synkron statistikuppdatering. Du kunde se *efter* att statistikuppdateringen hade slutförts om du redan hade en utökad evenemangssession igång och tittade för auto_stats händelse och filtrering på async kolumnen ställs in på 0. Den kolumnen i händelseutgången lades dock bara till i SQL Server 2017, och du måste också konfigurera en åtgärd som fångade något för att identifiera den inblandade frågan.
Nu i SQL Server 2019 finns det väntetypen WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE, och vid första anblicken verkar det som om det enkelt skulle tillåta dig att se om en fråga väntar på en synkron statistikuppdatering genom att bara titta i sys.dm_os_waiting_tasks för att se vad frågan är för närvarande väntar på.
Tyvärr är så inte fallet.
Termen "väntar" är lite missvisande här eftersom tråden i det här fallet faktiskt inte väntar. Den här nya väntetypen är ett exempel på vad som kallas en "förebyggande" väntan, där tråden växlar till ett läge där den förblir på processorn tills den är klar med sitt arbete. De flesta förebyggande väntetider är när en tråd ringer ett anrop utanför SQL Server (t.ex. för att få säkerhetsinformation från en domänkontrollant), men ibland gör en tråd något inuti SQL Server och måste slutföra det innan den eventuellt tvingas ge efter processorn eftersom dess 4ms trådkvantum har gått ut. Ingen av dessa saker är vad som händer här. I det här fallet registrerar tråden början av en förebyggande väntan med den nya väntetypen och uppdaterar sedan statistiken, vilket troligen medför andra *riktiga* väntan som PAGEIOLATCH_SH längs vägen. Det är inte förrän statistikuppdateringen har slutförts som den förebyggande väntetiden slutar och tas med i väntestatistiken.
Varför är detta en stor sak? Tja, DMV sys.dm_os_waiting_tasks visar väntetyperna för alla trådar som *verkligen* väntar, d.v.s. på vänteuppgiftslistan för en schemaläggare, så om den synkrona statistikuppdateringstråden inte väntar på WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE, så är den väntetypen kommer inte att visas i utgången av DMV. Den nya väntetypen kan inte användas för att se om en fråga för närvarande väntar på en statistikuppdatering.
Du kan enkelt bevisa detta för dig själv genom att göra följande:
- Skapa en tabell med några hundra tusen rader
- Skapa en statistik på en tabellkolumn och ange FULLSCAN och PERSIST_SAMPLE_PERCENT =ON som alternativ, vilket tvingar hela tabellen att läsas varje gång statistiken uppdateras
- Uppdatera tjugotusen rader
- Kontrollera databasen och kör DBCC DROPCLEANBUFFERS
- Gör en SELECT-sats med en WHERE-sats i kolumnen med statistiken du skapade
- Titta i sys.dm_os_waiting_tasks DMV efter sessions-ID för SELECT, så ser du att det troligen väntar på PAGEIOLATCH_SH när statistikuppdateringen läser igenom tabellen
Med den besvikelsen åt sidan finns det ett knep för att kunna se om en fråga väntar på en synkron statistikuppdatering. När en statistikuppdatering sker körs ett kommando som heter STATMAN, och du kan se det hända i utdata från sys.dm_exec_requests :status kommer att "avstängas" (även om tråden körs, som jag beskrev ovan), och kommandot kommer att vara "SELECT (STATMAN)."
Vilken användning är den nya väntetypen?
Även om den nya väntetypen inte kan användas som ett omedelbart sätt att tala om att en fråga väntar på en synkron statistikuppdatering, om den dyker upp i din vanliga väntestatistikanalys vet du att vissa frågor i arbetsbelastningen kan lida av dessa förseningar . Men det är ungefär gränsen för dess användbarhet såvitt jag är orolig. Såvida inte den genomsnittliga väntetiden visas som en oroande procentandel av din genomsnittliga frågekörningstid eller om du ständigt registrerar väntetider under korta tidsperioder för att möjliggöra korrekt analys, vet du inte säkert om det finns ett problem.
Detta är en väntetyp där väntetiden kan variera kraftigt, beroende på faktorerna jag nämnde tidigare. Därför skulle jag bara använda närvaron av denna väntetyp för att bli varnad om potentiella problem, och jag skulle vilja implementera en utökad händelsesession enligt beskrivningen ovan för att fånga instanser av synkrona statistikuppdateringar för att se om deras varaktighet är tillräckligt lång för att förtjäna vidta några korrigerande åtgärder.
Sammanfattning
Jag är inte säker på att tillägget av väntetypen WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE kommer att ändra om folk konfigurerar asynkrona statistikuppdateringar eller helt enkelt sköter allt statistikunderhåll själva, men åtminstone nu kommer du att kunna se om frågor väntar på synkron statistik uppdateringar och vidta ytterligare åtgärder.
Tills nästa gång, glad prestandafelsökning!