Introduktion
SQL Server-forespørgselsoptimering gør brug af statistik under forespørgselskompilering for at hjælpe med at bestemme den optimale forespørgselsplan. Som standard, hvis optimeringsværktøjet bemærker, at en statistik er forældet på grund af for mange ændringer i en tabel, vil den opdatere statistikken umiddelbart før forespørgselskompileringen kan fortsætte (kun den statistik, den har brug for, ikke al statistik for tabellen) .
Bemærk, at "for mange" er uspecifik, fordi det varierer efter version og om sporingsflag 2371 er aktiveret – se afsnittet AUTO_UPDATE_STATISTICS på denne side for detaljer.
Problemet med synkrone statistikopdateringer
Synkron opdatering af statistik før kompilering introducerer naturligvis en forsinkelse og gør, at forespørgslen tager længere tid at kompilere og udføre. Hvor stor en forsinkelse afhænger af flere faktorer, herunder:
- Hvor mange tabeller involveret i forespørgslen har nået grænsen for "for mange ændringer"
- Hvor mange statistikker for hver af disse tabeller skal opdateres, fordi de er nødvendige til kompilering
- Hvor mange rækker er der i de involverede tabeller
- Valgmulighederne angivet, da hver statistik blev oprettet (f.eks. FULLSCAN og PERSIST_SAMPLE_PERCENT=ON)
Så der kan være en tilsyneladende tilfældig forsinkelse, som kan forårsage problemer i nogle scenarier, især hvis en applikation har en meget lav forespørgselstimeout.
Undgå synkrone statistikopdateringer
Der er forskellige måder at undgå synkrone statistikopdateringer på, såsom:
- Indstilling af AUTO_UPDATE_STATISTICS til FRA, hvilket slår alle automatiske opdateringer fra og betyder, at du bliver nødt til at udføre din egen statistikvedligeholdelse for at undgå muligheden for suboptimale forespørgselsplaner fra forældede statistikker.
- Indstilling af AUTO_UPDATE_STATISTICS_ASYNC til ON, så når optimeringsværktøjet bemærker, at en statistik skal opdateres, fortsætter den med kompilering, og en baggrundsopgave opdaterer statistikken lidt senere. Dette virker kun, hvis du også har AUTO_UPDATE_STATISTICS indstillet til TIL.
- Udfør regelmæssig statistikvedligeholdelse, så automatiske synkrone eller asynkrone statistikopdateringer overhovedet ikke sker.
Der er en masse debat i SQL Server-fællesskabet om, hvorvidt man skal aktivere asynkrone statistikopdateringer. Jeg spurgte min dejlige kone, Kimberly L. Tripp, hvad hendes mening er, og hun anbefaler altid at aktivere det, og hun har glemt mere om statistik, end jeg nogensinde vil vide, så jeg tror på hende. ☺
Sporing af synkrone statistikopdateringer
Der har aldrig været en indlysende måde at fortælle, om en forespørgsel tog lang tid, fordi den ventede på en synkron statistikopdatering. Du kunne se *efter* at statistikopdateringen var fuldført, hvis du havde en udvidet begivenhedssession, der allerede kørte for at se auto_stats hændelse og filtrering på async kolonne indstilles til 0. Denne kolonne i hændelsesoutput blev dog kun tilføjet i SQL Server 2017, og du skulle også konfigurere en handling, der fangede noget for at identificere den involverede forespørgsel.
Nu i SQL Server 2019 er der ventetypen WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE, og ved første øjekast ser det ud til, at det nemt ville give dig mulighed for at se, om en forespørgsel venter på en synkron statistikopdatering ved blot at kigge i sys.dm_os_waiting_tasks for at se, hvad forespørgslen er i øjeblikket venter på.
Det er desværre ikke tilfældet.
Udtrykket "venter" er lidt misvisende her, da tråden i dette tilfælde faktisk ikke venter. Denne nye ventetype er et eksempel på det, der kaldes en "forebyggende" ventetid, hvor tråden skifter til en tilstand, hvor den forbliver på processoren, indtil den er færdig med sit arbejde. De fleste forebyggende ventetider er, når en tråd foretager et opkald uden for SQL Server (f.eks. for at få sikkerhedsoplysninger fra en domænecontroller), men nogle gange laver en tråd noget inde i SQL Server og skal fuldføre det, før det potentielt bliver tvunget til at give processoren efter. fordi dens 4ms trådkvante er udløbet. Ingen af disse ting er, hvad der sker her. I dette tilfælde registrerer tråden starten på en forebyggende ventetid med den nye ventetype og opdaterer derefter statistikken, hvilket sandsynligvis medfører andre *rigtige* ventetider som PAGEIOLATCH_SH undervejs. Det er ikke før statistikopdateringen er gennemført, at den forebyggende ventetid slutter og tages med i ventestatistikkens metrics.
Hvorfor er det en stor sag? Nå, DMV sys.dm_os_waiting_tasks viser ventetyperne for alle de tråde, der *virkelig* venter, dvs. på listen over ventende opgaver i en planlægger, så hvis den synkrone statistikopdateringstråd ikke venter på WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE, vil denne ventetype vises ikke i outputtet af DMV. Den nye ventetype kan ikke bruges til at se, om en forespørgsel i øjeblikket venter på en statistikopdatering.
Du kan nemt bevise dette for dig selv ved at gøre følgende:
- Opret en tabel med et par hundrede tusinde rækker
- Opret en statistik på en tabelkolonne, og angiv FULLSCAN og PERSIST_SAMPLE_PERCENT =ON som muligheder, hvilket tvinger hele tabellen til at blive læst, hver gang statistikken opdateres
- Opdater tyve tusinde rækker
- Tjek databasen og kør DBCC DROPCLEANBUFFERS
- Lav en SELECT-sætning med en WHERE-sætning i kolonnen med den statistik, du har oprettet
- Se i sys.dm_os_waiting_tasks DMV efter sessions-id'et for SELECT, og du vil se, at det sandsynligvis venter på PAGEIOLATCH_SH, mens statistikopdateringen læser gennem tabellen
Med den skuffelse til side, er der et trick til at kunne se, om en forespørgsel venter på en synkron statistikopdatering. Når der sker en statistikopdatering, kører en kommando kaldet STATMAN, og du kan se det ske i outputtet fra sys.dm_exec_requests :status vil blive "suspenderet" (selvom tråden kører, som jeg har beskrevet ovenfor), og kommandoen vil være "SELECT (STATMAN)."
Hvilken brug er den nye ventetype?
Selvom den nye ventetype ikke kan bruges som en øjeblikkelig måde at fortælle, at en forespørgsel venter på en synkron statistikopdatering, ved du, hvis den dukker op i din almindelige ventestatistikanalyse, at nogle forespørgsler i arbejdsbyrden kan lide under disse forsinkelser . Men det er omkring grænsen for dets anvendelighed, så vidt jeg er bekymret for. Medmindre den gennemsnitlige ventetid viser sig som en bekymrende procentdel af din gennemsnitlige udførelsestid for forespørgsler, eller du konstant registrerer ventetider over små perioder for at tillade korrekt analyse, ved du ikke med sikkerhed, om der er et problem.
Dette er en ventetype, hvor ventetiden kan variere voldsomt, afhængig af de faktorer, jeg nævnte tidligere. Derfor ville jeg kun bruge tilstedeværelsen af denne ventetype for at blive advaret om potentielle problemer, og jeg vil gerne implementere en udvidet begivenhedssession som beskrevet ovenfor for at fange forekomster af synkrone statistikopdateringer for at se, om deres varighed er lang nok til at fortjene tage nogle korrigerende handlinger.
Oversigt
Jeg er ikke sikker på, at tilføjelsen af ventetypen WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE vil ændre, om folk konfigurerer asynkrone statistikopdateringer eller blot udfører al statistikvedligeholdelse selv, men i det mindste nu vil du være i stand til at se, om forespørgsler venter på synkron statistik opdateringer og tag nogle yderligere handlinger.
Indtil næste gang, god ydelsesfejlfinding!