sql >> Databasteknik >  >> RDS >> Database

Hur automatiska uppdateringar av statistik kan påverka frågeprestanda

I mitt tidigare inlägg utforskade jag olika metoder för att spåra automatiska uppdateringar av statistik för att avgöra om de påverkade frågeprestanda. I den senare hälften av inlägget inkluderade jag alternativ, varav ett var att aktivera databasinställningen Automatisk uppdatering av statistik asynkront. I det här inlägget vill jag titta på hur frågeprestanda förändras när den automatiska uppdateringen sker innan frågan körs, och vad som händer med prestanda om uppdateringen är asynkron.

Inställningen

Jag började med en kopia av AdventureWorks2012-databasen och skapade sedan en kopia av SalesOrderHeader-tabellen med över 200 miljoner rader med detta skript. Tabellen har ett klustrat index på SalesOrderID och ett icke-klustrat index på CustomerID, OrderDate, SubTotal. [Obs:om du ska göra upprepade tester, ta en säkerhetskopia av denna databas nu för att spara lite tid]. Efter att ha laddat in data och skapat det icke-klustrade indexet, verifierade jag radantalet och beräknade hur många rader (ungefär) som skulle behöva modifieras för att anropa en automatisk uppdatering.

SELECTOBJECT_NAME([p].[object_id]) [TabellName],[si].[name] [IndexName],[au].[type_desc] [Typ],[p].[rader] [RowCount], ([p].[rader]*.20) + 500 [UpdateThreshold],[au].total_pages [PageCount],(([au].[total_pages]*8)/1024)/1024 [TotalGB]FRÅN [sys ].[partitioner] [p]JOIN [sys].[allocation_units] [au] PÅ [p].[partition_id] =[au].[container_id]JOIN [sys].[indexerar] [si] på [p] .[object_id] =[si].object_id och [p].[index_id] =[si].[index_id]WHERE [p].[object_id] =OBJECT_ID(N'Sales.Big_SalesOrderHeader');


Big_SalesOrderHeader CIX och NCI Information

Jag har också verifierat den aktuella statistikhuvudet för indexet:

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


NCI-statistik:vid start

Jag skapade sedan den lagrade proceduren som jag skulle använda för att testa. Det är en enkel procedur som frågar efter Sales.Big_SalesOrderHeader och aggregerar försäljningsdata efter CustomerID och OrderDate för analys:

SKAPA PROCEDUR Sales.usp_GetCustomerStats@CustomerID INT,@StartDate DATETIME,@EndDate DATETIMEASBEGIN SET NOCOUNT ON; VÄLJ Kund-ID, DATEPART(ÅR, OrderDatum), DATEPART(MONTH, OrderDate), COUNT([SalesOrderID]) som beräknat FRÅN [Sales].[Big_SalesOrderHeader] WHERE CustomerID =@Kund-ID OCH OrderDatum MELLAN @StartDatum och @EndDateID GROUP, BY CustomerID. DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate) ORDER BY DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate);END

Slutligen, innan jag körde den lagrade proceduren, skapade jag en Extended Event-session så att jag kunde spåra frågans varaktighet med sp_statement_starting och sp_statement_completed. Jag lade också till händelsen auto_stats, för även om jag inte förväntade mig att en uppdatering skulle ske, ville jag använda samma sessionsdefinition senare.

SKAPA EVENT 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_startingADD 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=CANUP_GO_STÅR,Testet 

Jag startade sessionen Extended Events och körde sedan den lagrade proceduren flera gånger med olika kund-ID:

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.9GOusCStatom', '2012-08-31:59.9GOusCetom' 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.000:01.000:' -30 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 17061, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales 3-1C1C1C1C1C1C1C1C1C1C 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', '2929:53 'GOEXEC Sales.usp_GetCustomerStats 29837, '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 0:00150, '15010150, '15010150:000150:, '2013-03-31 23:59:59.997'GO

Jag verifierade antalet exekveringar och planen genom att fråga i procedurens cache:

SELECTOBJECT_NAME([st].[objectid]),[st].[text],[qs].[execution_count],[qs].[creation_time],[qs].[last_execution_time],[qs]. [min_arbetartid],[qs].[max_arbetartid],[qs].[min_logical_reads],[qs].[max_logical_reads],[qs].[min_elapsed_time],[qs].[max_elapsed_time],[qp].[query_plan ]FRÅN [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) VAR [st].[text] SOM '%usp_GetCustomerStats%'OCH OBJECT_NAME([st].[objectid]) ÄR INTE NULL;


Planera cache:vid start


Frågeplan för lagrad procedur med SQL Sentry Plan Explorer

Jag kunde se att planen skapades 2014-04-08 18:59:39.850. Med planen i cachen stoppade jag sessionen Extended Events:

ÄNDRA HÄNDELSESESSION [StatsUpdate_QueryPerf]PÅ SERVERSTATE =STOPP;

Därefter lade jag till cirka 47 miljoner rader med data till tabellen med detta skript, långt över den tröskel som krävs för att ogiltigförklara den aktuella statistiken. Efter att ha lagt till data verifierade jag antalet rader i tabellen:


Big_SalesOrderHeader CI:Efter dataladdning

Innan jag körde om min lagrade procedur kontrollerade jag planens cache för att se till att ingenting hade ändrats, och verifierade att statistiken ännu inte hade uppdaterats. Kom ihåg att även om statistiken var ogiltig vid denna tidpunkt kommer den inte att uppdateras förrän en fråga som använder statistiken körs (för referens:Understanding When Statistics Will Automatically Update). För det sista steget startade jag sessionen Extended Events igen och körde sedan den lagrade proceduren flera gånger. Efter dessa avrättningar kontrollerade jag planens cache igen:


Planera cache:efter dataladdning

Antalet execution_count är 8 igen, och om vi tittar på create_time för planen kan vi se att den har ändrats till 2014-04-08 19:32:52.913. Om vi ​​kontrollerar planen kan vi se att den är densamma, även om planen kompilerades om:


Frågeplan för lagrad procedur med SQL Sentry Plan Explorer

Analys av utdata för utökade händelser

Jag tog den första filen Extended Events – innan data laddades – och öppnade den i SSMS och använde sedan ett filter så att endast uttalanden från den lagrade proceduren listades:


Utgång av utökade händelser:Efter initial SP-exekvering

Du kan se att det finns åtta (8) körningar av den lagrade proceduren, med frågelängd som varierar något.

Jag tog den andra filen Extended Events – efter att data laddats – öppnade den SSMS och filtrerade igen så att endast uttalanden från den lagrade proceduren, såväl som auto_stats-händelser, listades:


Utökad händelseutdata:SP-exekvering efter dataladdning

Utdata är trunkerat, eftersom det inte behövs allt för att visa huvudresultatet. De blå markerade posterna representerar den första exekveringen av den lagrade proceduren, och notera att det finns flera steg – uppdateringen av statistik är en del av exekveringen. SELECT-satsen startar (attach_activity_id.seq =3), och uppdateringarna av statistiken körs sedan. I vårt exempel har vi faktiskt uppdateringar av tre statistik. När den senaste uppdateringen är klar (attach_activity_id.seq =11) startar och slutförs den lagrade proceduren (attach_activity_id.seq =13 och attach_activity_id.seq =14). Intressant nog finns det en andra sp_statement_starting-händelse för den lagrade proceduren (förmodligen ignoreras den första), så den totala varaktigheten för den lagrade proceduren beräknas utan uppdateringen av statistik.

I det här scenariot gör att statistiken uppdateras automatiskt omedelbart – det vill säga när en fråga som använder ogiltiga statistik körs – gör att frågan körs längre, även om söklängden baserad på händelsen sp_statement_completed fortfarande är mindre än 14000. Slutresultatet är att det finns är ingen fördel med att fråga prestanda, eftersom planen är exakt densamma före och efter statistikuppdateringen. I det här scenariot ändras inte frågeplanen och exekveringslängden efter att mer data har lagts till i tabellen, så uppdateringen till statistik hindrar bara dess prestanda. Låt oss nu se vad som händer när vi aktiverar alternativet Automatisk uppdatering av statistik asynkront.

Testet, version 2

Vi börjar med att återställa till säkerhetskopian som jag tog innan vi startade det första testet. Jag återskapade den lagrade proceduren och ändrade sedan databasalternativet för att uppdatera statistik asynkront:

ANVÄND [master];GOALTER DATABASE [AdventureWorks2012_Big] STÄLL IN AUTO_UPDATE_STATISTICS_ASYNC PÅ MED NO_WAITGO

Jag startade sessionen Extended Events och körde den lagrade proceduren flera gånger med olika kund-ID:

ALTER EVENT SESSION [StatsUpdate_QueryPerf]PÅ SERVERSTATE =START;GO EXEC Sales.usp_GetCustomerStats11331, '2012-08-01 00:00:00.000', '2012-08-31 23.9CGStatus:59.5CGStatus, 23:59C2012-08-31:59:5C000, 2012-08-31 23:59C, 23:59C0000, 23:59C, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11506, '2012-11-01 00:00:00', '12002'00, '12002'00, '12002'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'01CStat:01C1_Get:01C101:01C:01C:01C: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:37Cetus:37Customs:39Customs:39.EXE:39.EXE:39.EXE '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15750, '2013-03-01 00:00:3-00, '3201:00', '3200:00' :59:59.997'GO

Jag verifierade antalet exekveringar och planen genom att fråga i procedurens cache:


Planera cache:vid start, test 2


Frågeplan för lagrad procedur med SQL Sentry Plan Explorer

För detta test skapades planen 2014-04-08 21:15:55.490. Jag stoppade den utökade händelsesessionen och lade igen cirka 47 miljoner rader med data till tabellen, med samma fråga som tidigare.

När uppgifterna väl hade lagts till kontrollerade jag planens cache för att se till att ingenting hade ändrats och verifierade att statistiken ännu inte hade uppdaterats. Slutligen startade jag sessionen Extended Events igen och körde sedan den lagrade proceduren åtta gånger till. En sista titt i planens cache visade execution_count vid 16 och en create_time på 2014-04-08 21:15:55.490. execution_count och create_time visar att statistiken inte har uppdaterats, eftersom planen inte har tömts från cachen ännu (om den hade gjort det skulle vi ha en senare create_time och ett execution_count på 8).


Planera cache:Efter dataladdning, test 2

Om vi ​​öppnar utgången för Extended Events från efter dataladdningen i SSMS, och igen filtrerar så att vi bara ser uttalanden från den lagrade proceduren, såväl som auto_stats-händelser, hittar vi detta (observera att utgången är uppdelad i två skärmdumpar):


Utökad händelseutdata:Test 2, SP-exekvering efter dataladdning, del I


Utvidgad händelseutdata:Test 2, SP-exekvering efter dataladdning, del II

Händelserna för exekvering av det första anropet av den lagrade proceduren är markerade i blått – de börjar 2014-04-08 21:54:14.9480607 och det finns sju (7) händelser. Observera att det finns tre (3) auto_stats-händelser, men ingen av dem slutförs, som vi såg när alternativet Automatisk uppdatering av statistik asynkront inaktiverades. Du kommer att märka att den automatiska uppdateringen startar för en av statistiken nästan omedelbart (2014-04-08 21:54:14.9481288), och det är tre händelser som har den röda texten 'Stat Update #1' bredvid sig. Den statistikuppdateringen slutar 2014-04-08 21:54:16.5392219, knappt två sekunder efter att den startar, men efter att alla andra körningar av proceduren har slutförts. Det är därför execution_count från sys.dm_exec_query_stats visar 16. Från XE-utgången kan vi se att de andra statistikuppdateringarna sedan slutförs (Stat Update #2 och Stat Update #3). Alla uppdateringar är asynkrona med den initiala lagrade procedurens exekvering.

Sammanfattning

Som du kan se har automatiska uppdateringar av statistik potential att negativt påverka frågeprestanda. Graden av påverkan kommer att bero på mängden data som måste läsas för att uppdatera statistiken och systemresurserna. I vissa fall ökar frågeprestandan bara med millisekunder och är troligen omärklig för användarna. Andra gånger kan varaktigheten öka dramatiskt, vilket sedan påverkar slutanvändarens upplevelse. I de fall då frågeplanen inte ändras efter en uppdatering av statistik, är det väl värt att överväga att aktivera alternativet Automatisk uppdatering av statistik asynkront, för att minska påverkan på frågeprestanda.


  1. Jämföra objekt efter värde. Del 6:Struktur Jämställdhetsimplementering

  2. Hur man infogar flera rader i en enda SQL-fråga – Veckans intervjufråga #069

  3. Android med rum - Hur man ställer in en främmande nyckel på null

  4. GeoDjango på Windows:Kunde inte hitta GDAL-biblioteket / OSError:[WinError 126] Den angivna modulen kunde inte hittas