sql >> Database teknologi >  >> RDS >> Database

Hvordan automatiske opdateringer til statistik kan påvirke forespørgselsydeevne

I mit tidligere indlæg udforskede jeg forskellige metoder til at spore automatiske opdateringer til statistik for at afgøre, om de påvirkede forespørgselsydeevnen. I den sidste halvdel af indlægget inkluderede jeg muligheder, hvoraf den ene var at aktivere databaseindstillingen Automatisk opdatering af statistik asynkront. I dette indlæg vil jeg se på, hvordan forespørgselsydeevne ændres, når den automatiske opdatering sker før forespørgselsudførelse, og hvad der sker med ydeevnen, hvis opdateringen er asynkron.

Opsætningen

Jeg startede med en kopi af AdventureWorks2012-databasen og lavede derefter en kopi af SalesOrderHeader-tabellen med over 200 millioner rækker ved hjælp af dette script. Tabellen har et klynget indeks på SalesOrderID og et ikke-clusteret indeks på CustomerID, OrderDate, SubTotal. [Bemærk:Hvis du skal udføre gentagne tests, skal du tage en sikkerhedskopi af denne database på dette tidspunkt for at spare dig selv for lidt tid]. Efter at have indlæst dataene og oprettet det ikke-klyngede indeks, bekræftede jeg rækkeantallet og beregnede, hvor mange rækker (ca.) der skulle modificeres for at fremkalde en automatisk opdatering.

SELECTOBJECT_NAME([p].[object_id]) [Tabelnavn],[si].[navn] [IndexName],[au].[type_desc] [Type],[p].[rows] [RowCount], ([p].[rows]*.20) + 500 [UpdateThreshold],[au].total_pages [PageCount],(([au].[total_pages]*8)/1024)/1024 [TotalGB]FRA [sys ].[partitioner] [p]JOIN [sys].[allokeringsenheder] [au] TIL [p].[partition_id] =[au].[container_id]JOIN [sys].[indekser] [si] på [p] .[object_id] =[si].object_id og [p].[index_id] =[si].[index_id]WHERE [p].[object_id] =OBJECT_ID(N'Sales.Big_SalesOrderHeader');


Big_SalesOrderHeader CIX og NCI Information

Jeg har også bekræftet den aktuelle statistikheader for indekset:

DBCC SHOW_STATISTICS ('Sales.Big_SalesOrderHeader',[IX_Big_SalesOrderHeader_CustomerID_OrderDate_SubTotal]);


NCI-statistik:Ved start

Jeg oprettede derefter den lagrede procedure, som jeg ville bruge til at teste. Det er en ligetil procedure, der forespørger Sales.Big_SalesOrderHeader og samler salgsdata efter kunde-id og ordredato til analyse:

OPRET PROCEDURE Sales.usp_GetCustomerStats@CustomerID INT,@StartDate DATETIME,@EndDate DATETIMEASBEGIN SET NOCOUNT ON; VÆLG Kunde-ID, DATODEL(ÅR, Ordredato), DATODEL(MÅNED, Ordredato), ANTAL([Salgsordre-ID]) som beregnet FRA [Salg].[Big_SalesOrderHeader] HVOR Kunde-ID =@Kunde-ID OG Ordredato MELLEM @Startdato og @Kunde-ID GRUPPE, BY CustomerID. DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate) ORDER BY DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate);END

Til sidst, før jeg udførte den lagrede procedure, oprettede jeg en Extended Events-session, så jeg kunne spore forespørgselsvarighed ved hjælp af sp_statement_starting og sp_statement_completed. Jeg tilføjede også hændelsen auto_stats, for selvom jeg ikke forventede en opdatering, ville jeg bruge den samme sessionsdefinition senere.

OPRET BEGIVENHED SESSION [StatsUpdate_QueryPerf]PÅ SERVERADD EVENT sqlserver.auto_stats,ADD EVENT sqlserver.sp_statement_completed(SET collect_statement=(1)),ADD EVENT sqlserver.sp_statement_package=tempe.event TARGETfil'0 StatsUpdate_QueryPerf.xel')WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SEKUNDER,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE_MODE=CAUP_GO-TRACKON,=START_GODKENDT_GODKENDELSE); 

Testen

Jeg startede sessionen udvidede hændelser og udførte derefter den lagrede procedure flere gange ved hjælp af forskellige kunde-id'er:

ALTER EVENT SESSION [StatsUpdate_QueryPerf]ON SERVERSTATE =START;GO EXEC Sales.usp_GetCustomerStats 11331, '2012-08-01 00:00:00.000', '2012-08-31:59.9GOusCusCestom', '2012-08-31:59.9GOussCetom'. 11330, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11506, '2012-11-001:01:0001,01:0001:01:00. -30 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 17061, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'ustom_G Sales1C-1C1C1C1C2013-2013-2013-2013 01 00:00:00.000', '2013-03-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 15131, '2013-02-01 00:00:00.000-', '3929:53', '29278:53 'GOEXEC Sales.usp_GetCustomerStats 29837, '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 00:00150, '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 0:000150:, '2013-03-31 23:59:59.997'GO

Jeg bekræftede eksekveringsantallet og planen ved at forespørge i procedurecachen:

SELECTOBJECT_NAME([st].[objekt-id]),[st].[tekst],[qs].[execution_count],[qs].[creation_time],[qs].[last_execution_time],[qs]. [min_worker_time],[qs].[max_worker_time],[qs].[min_logical_reads],[qs].[max_logical_reads],[qs].[min_elapsed_time],[qs].[max_elapsed_time],[qp].[query_plan ]FRA [sys].[dm_exec_query_stats] [qs]CROSS APPLY [sys].[dm_exec_sql_text]([qs].plan_handle) [st]CROSS APPLY [sys].[dm_exec_query_plan]([qs].plan]_handle) [qs].plan_handle) HVOR [st].[text] SOM '%usp_GetCustomerStats%'OG OBJECT_NAME([st].[objectid]) ER IKKE NULL;


Plan cache:Ved start


Forespørgselsplan for lagret procedure ved hjælp af SQL Sentry Plan Explorer

Jeg kunne se, at planen blev oprettet 2014-04-08 18:59:39.850. Med planen i cachen stoppede jeg sessionen med udvidede begivenheder:

ALTER EVENT SESSION [StatsUpdate_QueryPerf]ON SERVERSTATE =STOP;

Dernæst tilføjede jeg omkring 47 millioner rækker af data til tabellen ved hjælp af dette script, et godt stykke over den tærskel, der er nødvendig for at ugyldiggøre den aktuelle statistik. Efter at have tilføjet dataene, bekræftede jeg antallet af rækker i tabellen:


Big_SalesOrderHeader CI:Efter dataindlæsning

Før jeg kørte min lagrede procedure igen, tjekkede jeg planens cache for at sikre, at intet var ændret, og bekræftede, at statistikken endnu ikke var opdateret. Husk, at selvom statistikkerne blev ugyldige på dette tidspunkt, opdateres de ikke, før en forespørgsel, der bruger statistikken, udføres (til reference:Understanding When Statistics Will Automatically Update). Til det sidste trin startede jeg sessionen Udvidede begivenheder igen og kørte derefter den lagrede procedure flere gange. Efter disse henrettelser tjekkede jeg planens cache igen:


Planlæg cache:Efter dataindlæsning

Udførelsestallet er igen 8, og hvis vi ser på oprettelsestidspunktet for planen, kan vi se, at det er ændret til 2014-04-08 19:32:52.913. Hvis vi tjekker planen, kan vi se, at den er den samme, selvom planen blev genkompileret:


Forespørgselsplan for lagret procedure ved hjælp af SQL Sentry Plan Explorer

Analyse af output for udvidede hændelser

Jeg tog den første Extended Events-fil – før data blev indlæst – og åbnede den i SSMS, og anvendte derefter et filter, så kun udsagn fra den lagrede procedure blev vist:


Udvidet hændelsesoutput:Efter indledende SP-udførelse

Du kan se, at der er otte (8) udførelser af den lagrede procedure, med forespørgselsvarigheder, der varierer lidt.

Jeg tog den anden Extended Events-fil – efter data var indlæst – åbnede den SSMS og filtrerede igen, så kun udsagn fra den lagrede procedure, såvel som auto_stats-hændelser, blev opført:


Udvidet hændelsesoutput:SP-udførelse efter dataindlæsning

Outputtet er afkortet, da det ikke hele er nødvendigt for at vise hovedresultatet. De blå fremhævede poster repræsenterer den første udførelse af den lagrede procedure, og bemærk, at der er flere trin - opdateringen til statistik er en del af udførelsen. SELECT-sætningen starter (attach_activity_id.seq =3), og opdateringerne til statistik udføres derefter. I vores eksempel har vi faktisk opdateringer til tre statistikker. Når den sidste opdatering er fuldført (attach_activity_id.seq =11), starter og afsluttes den lagrede procedure (attach_activity_id.seq =13 og attach_activity_id.seq =14). Interessant nok er der en anden sp_statement_starting-hændelse for den lagrede procedure (formodentlig ses der bort fra den første), så den samlede varighed for den lagrede procedure beregnes uden opdateringen til statistik.

I dette scenarie vil det at få statistikken automatisk opdateret med det samme – det vil sige når en forespørgsel, der bruger ugyldig statistik udføres – at forespørgslen kører længere, selvom forespørgselsvarigheden baseret på sp_statement_completed-hændelsen stadig er mindre end 14000. Slutresultatet er, at der er ingen fordel at forespørge ydeevne, da planen er nøjagtig den samme før og efter statistikopdateringen. I dette scenarie ændres forespørgselsplanen og udførelsesvarigheden ikke, efter at flere data er føjet til tabellen, så opdateringen til statistik hindrer kun dens ydeevne. Lad os nu se, hvad der sker, når vi aktiverer muligheden Automatisk opdatering af statistik asynkront.

Testen, version 2

Vi starter med at gendanne til den backup, som jeg tog, før vi startede den første test. Jeg genskabte den lagrede procedure og ændrede derefter databaseindstillingen for at opdatere statistik asynkront:

BRUG [master];GOALTER DATABASE [AdventureWorks2012_Big] SÆT AUTO_UPDATE_STATISTICS_ASYNC TIL MED NO_WAITGO

Jeg startede den udvidede begivenhedssession og udførte igen den lagrede procedure flere gange ved at bruge forskellige kunde-id'er:

ALTER EVENT SESSION [StatsUpdate_QueryPerf]PÅ SERVERSTATE =START;GO EXEC Sales.usp_GetCustomerStats11331, '2012-08-01 00:00:00.000', '2012-08-31 23.9CGetus123:59C0000, '2012-08-31:59.9C0000000000000, '2012-08-37:59.9C00123:59C000' '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11506, '2012-11-01 00:002:00, '12010:00, '12010:00' :59:59.997'GOEXEC Sales.usp_GetCustomerStats17061, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp1-01:301C:01Stat:301C1-01:01C:01C1,01C1,01C1,01C1,01 00.000', '2013-03-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15131, '2013-02-01 00:00:00.000', '2013-02-598:2013-02-598:23.EXEGus:52.EXE.9.598:23.EXE.9.7.9.9.9. '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15750, '2013-03-01 00:00:00'00, '3201:00'00, '3201:00' :59:59.997'GO

Jeg bekræftede eksekveringsantallet og planen ved at forespørge i procedurecachen:


Planlæg cache:ved start, test 2


Forespørgselsplan for lagret procedure ved hjælp af SQL Sentry Plan Explorer

Til denne test blev planen oprettet 2014-04-08 21:15:55.490. Jeg stoppede Extended Events-sessionen og tilføjede igen omkring 47 millioner rækker data til tabellen ved at bruge samme forespørgsel som før.

Da dataene var blevet tilføjet, tjekkede jeg planens cache for at sikre, at intet var ændret, og bekræftede, at statistikken endnu ikke var opdateret. Til sidst startede jeg sessionen Udvidede begivenheder igen og kørte derefter den lagrede procedure otte gange mere. Et sidste kig ind i planens cache viste execution_count ved 16 og en create_time på 2014-04-08 21:15:55.490. execution_count og create_time viser, at statistikken ikke er opdateret, da planen ikke er blevet tømt fra cachen endnu (hvis den havde, ville vi have en senere create_time og en execution_count på 8).


Planlæg cache:Efter dataindlæsning, test 2

Hvis vi åbner Extended Events-outputtet fra efter dataindlæsningen i SSMS, og igen filtrerer, så vi kun ser udsagn fra den lagrede procedure, samt auto_stats-hændelser, finder vi dette (bemærk, at outputtet er opdelt i to skærmbilleder):


Udvidet hændelsesoutput:Test 2, SP-udførelse efter dataindlæsning, del I


Udvidet hændelsesoutput:Test 2, SP-udførelse efter dataindlæsning, del II

Begivenhederne for udførelsen af ​​det første opkald af den lagrede procedure er fremhævet med blåt – de starter 2014-04-08 21:54:14.9480607, og der er syv (7) hændelser. Bemærk, at der er tre (3) auto_stats-hændelser, men ingen af ​​dem fuldføres, som vi så, da indstillingen Automatisk opdatering af statistik asynkront blev deaktiveret. Du vil bemærke, at den automatiske opdatering starter for en af ​​statistikkerne næsten med det samme (2014-04-08 21:54:14.9481288), og det er tre begivenheder, der har den røde tekst 'Stat Update #1' ud for sig. Den statistikopdatering slutter 2014-04-08 21:54:16.5392219, lige under to sekunder efter den er startet, men efter at alle andre udførsler af proceduren er afsluttet. Dette er grunden til, at execution_count fra sys.dm_exec_query_stats viser 16. Fra XE-outputtet kan vi se, at de andre statistikopdateringer derefter fuldføres (Stat Update #2 og Stat Update #3). Alle opdateringer er asynkrone med den indledende lagrede procedures udførelse.

Oversigt

Som du kan se, har automatiske opdateringer af statistik potentiale til at påvirke forespørgselsydeevne negativt. Graden af ​​påvirkning vil afhænge af mængden af ​​data, der skal læses for at opdatere statistikken, og systemressourcerne. I nogle tilfælde øges forespørgselsydeevnen kun med millisekunder og er højst sandsynligt umærkelig for brugerne. Andre gange kan varigheden stige dramatisk, hvilket så påvirker slutbrugeroplevelsen. I det tilfælde, hvor forespørgselsplanen ikke ændres efter en opdatering af statistikker, er det værd at overveje at aktivere Auto Update Statistics Asynchronously-indstillingen for at mindske indvirkningen på forespørgselsydeevnen.


  1. Visual Studio:ContextSwitchDeadlock

  2. Hvordan opdaterer jeg fra en SELECT i SQL Server?

  3. SQL Server-streng eller binære data vil blive afkortet

  4. Hvordan får man rækkeantal i sqlite ved hjælp af Android?