sql >> Database >  >> RDS >> Database

Hoe automatische updates van statistieken de prestaties van zoekopdrachten kunnen beïnvloeden

In mijn vorige bericht heb ik verschillende methoden onderzocht om automatische updates van statistieken bij te houden om te bepalen of ze de queryprestaties beïnvloeden. In de tweede helft van het bericht heb ik opties opgenomen, waaronder het inschakelen van de Auto Update Statistics Asynchroon database-instelling. In dit bericht wil ik bekijken hoe de prestaties van query's veranderen wanneer de automatische update plaatsvindt voordat de query wordt uitgevoerd, en wat er met de prestaties gebeurt als de update asynchroon is.

De opzet

Ik begon met een kopie van de AdventureWorks2012-database en maakte vervolgens een kopie van de SalesOrderHeader-tabel met meer dan 200 miljoen rijen met behulp van dit script. De tabel heeft een geclusterde index op SalesOrderID en een niet-geclusterde index op CustomerID, OrderDate, SubTotal. [Opmerking:als u herhaalde tests gaat doen, maak dan op dit moment een back-up van deze database om uzelf wat tijd te besparen]. Na het laden van de gegevens en het maken van de niet-geclusterde index, heb ik het aantal rijen geverifieerd en berekend hoeveel rijen (ongeveer) moeten worden aangepast om een ​​automatische update uit te voeren.

SELECTOBJECT_NAME([p].[object_id]) [TableName],[si].[name] [IndexName],[au].[type_desc] [Type],[p].[rows] [RowCount], ([p].[rijen]*.20) + 500 [UpdateThreshold],[au].total_pages [PageCount],(([au].[total_pages]*8)/1024)/1024 [TotalGB]FROM [sys ].[partities] [p]JOIN [sys].[allocation_units] [au] ON [p].[partition_id] =[au].[container_id]JOIN [sys].[indexes] [si] op [p] .[object_id] =[si].object_id en [p].[index_id] =[si].[index_id]WHERE [p].[object_id] =OBJECT_ID(N'Sales.Big_SalesOrderHeader');


Big_SalesOrderHeader CIX- en NCI-informatie

Ik heb ook de huidige statistiekenkop voor de index geverifieerd:

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


NCI-statistieken:bij het begin

Vervolgens heb ik de opgeslagen procedure gemaakt die ik zou gebruiken om te testen. Het is een eenvoudige procedure die Sales.Big_SalesOrderHeader doorzoekt en verkoopgegevens verzamelt op CustomerID en OrderDate voor analyse:

PROCEDURE MAKEN Sales.usp_GetCustomerStats@CustomerID INT,@StartDate DATETIME,@EndDate DATETIMEASBEGIN STEL NOCOUNT IN; SELECTEER CustomerID, DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate), COUNT([SalesOrderID]) zoals berekend FROM [Sales].[Big_SalesOrderHeader] WHERE CustomerID =@CustomerID AND OrderDate TUSSEN @StartDate en @EndDate GROUP BY CustomerID, DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate) ORDER BY DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate);END

Ten slotte heb ik, voordat ik de opgeslagen procedure uitvoerde, een Extended Events-sessie gemaakt, zodat ik de duur van de query kon volgen met sp_statement_starting en sp_statement_completed. Ik heb ook de gebeurtenis auto_stats toegevoegd, want hoewel ik niet had verwacht dat er een update zou plaatsvinden, wilde ik dezelfde sessiedefinitie later gebruiken.

CREATE EVENT SESSIE [StatsUpdate_QueryPerf]OP SERVERADD EVENT sqlserver.auto_stats,ADD EVENT sqlserver.sp_statement_completed(SET collect_statement=(1)),ADD EVENT sqlserver.sp_statement_startingADD TARGET package0.event_file'(SET bestandsnaam) StatsUpdate_QueryPerf.xel')MET (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDEN,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NALSTATE_MODE=NAL,=TRACK_CAUSpreUP,=TRACK_CAUS 

De Test

Ik startte de Extended Events-sessie en voerde vervolgens de opgeslagen procedure meerdere keren uit, met verschillende klant-ID's:

ALTER EVENT SESSIE [StatsUpdate_QueryPerf]OP SERVERSTATE =START;GA EXEC Sales.usp_GetCustomerStats 11331, '2012-08-01 00:00:00.000', '2012-08-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11330, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11506, '2012-11-01 00:00:00.000', '2012-11 -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.usp_GetCustomerStats 11711, '2013-03- 01 00:00:00.000', '2013-03-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 15131, '2013-02-01 00:00:00.000', '2013-02-28 23:59:59.997 'GOEXEC Sales.usp_GetCustomerStats 29837, '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 15750, '2013-03-01 00:00:00.000' , '2013-03-31 23:59:59.997'GO

Ik heb het aantal uitvoeringen en het plan geverifieerd door de procedurecache op te vragen:

SELECTOBJECT_NAME([st].[objectid]),[st].[text],[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 ]FROM [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) [qp] WAAR [st].[text] LIKE '%usp_GetCustomerStats%'AND OBJECT_NAME([st].[objectid]) NIET NULL IS;


Plancache:aan het begin


Queryplan voor opgeslagen procedure, met SQL Sentry Plan Explorer

Ik kon zien dat het plan is gemaakt op 2014-04-08 18:59:39.850. Met het plan in het cachegeheugen, heb ik de Extended Events-sessie gestopt:

ALTER EVENT SESSIE [StatsUpdate_QueryPerf]OP SERVERSTATE =STOP;

Vervolgens heb ik met dit script ongeveer 47 miljoen rijen gegevens aan de tabel toegevoegd, ruim boven de drempel die nodig is om de huidige statistieken ongeldig te maken. Nadat ik de gegevens had toegevoegd, heb ik het aantal rijen in de tabel geverifieerd:


Big_SalesOrderHeader CI:na het laden van gegevens

Voordat ik mijn opgeslagen procedure opnieuw uitvoerde, controleerde ik de plancache om er zeker van te zijn dat er niets was veranderd en controleerde ik of de statistieken nog niet waren bijgewerkt. Onthoud dat, ook al zijn de statistieken op dit punt ongeldig gemaakt, ze niet worden bijgewerkt totdat een query wordt uitgevoerd die de statistiek gebruikt (ter referentie:begrijpen wanneer statistieken automatisch worden bijgewerkt). Voor de laatste stap startte ik de Extended Events-sessie opnieuw en voerde ik de opgeslagen procedure meerdere keren uit. Na die uitvoeringen heb ik de plancache opnieuw gecontroleerd:


Plancache:na het laden van gegevens

De uitvoering_telling is weer 8, en als we kijken naar de create_time van het plan, kunnen we zien dat deze is gewijzigd in 2014-04-08 19:32:52.913. Als we het plan controleren, kunnen we zien dat het hetzelfde is, ook al is het plan opnieuw gecompileerd:


Queryplan voor opgeslagen procedure, met SQL Sentry Plan Explorer

Analyse van de output van uitgebreide gebeurtenissen

Ik nam het eerste Extended Events-bestand - voordat de gegevens werden geladen - en opende het in SSMS, en paste vervolgens een filter toe zodat alleen statements van de opgeslagen procedure werden weergegeven:


Uitvoer van uitgebreide gebeurtenissen:na initiële SP-uitvoering

U kunt zien dat er acht (8) uitvoeringen zijn van de opgeslagen procedure, met een vraagduur die enigszins varieert.

Ik nam het tweede Extended Events-bestand - nadat de gegevens waren geladen - opende het SSMS en filterde opnieuw zodat alleen statements van de opgeslagen procedure, evenals auto_stats-gebeurtenissen, werden weergegeven:


Uitvoer van uitgebreide gebeurtenissen:SP-uitvoering na laden van gegevens

De uitvoer wordt afgekapt, omdat het niet allemaal nodig is om het hoofdresultaat weer te geven. De blauw gemarkeerde items vertegenwoordigen de eerste uitvoering van de opgeslagen procedure en merk op dat er meerdere stappen zijn - de update naar statistieken maakt deel uit van de uitvoering. De SELECT-instructie wordt gestart (attach_activity_id.seq =3) en de updates voor statistieken worden vervolgens uitgevoerd. In ons voorbeeld hebben we eigenlijk updates voor drie statistieken. Zodra de laatste update is voltooid (attach_activity_id.seq =11), wordt de opgeslagen procedure gestart en voltooid (attach_activity_id.seq =13 en attach_activity_id.seq =14). Interessant genoeg is er een tweede sp_statement_starting-gebeurtenis voor de opgeslagen procedure (vermoedelijk wordt de eerste genegeerd), dus de totale duur van de opgeslagen procedure wordt berekend zonder de update naar statistieken.

In dit scenario zorgt het automatisch bijwerken van statistieken, dat wil zeggen wanneer een query die ongeldige statistieken gebruikt, wordt uitgevoerd, ervoor dat de query langer wordt uitgevoerd, ook al is de duur van de query op basis van de sp_statement_completed-gebeurtenis nog steeds minder dan 14000. Het eindresultaat is dat er is geen voordeel voor de queryprestaties, omdat het plan precies hetzelfde is voor en na de update van de statistieken. In dit scenario veranderen het queryplan en de uitvoeringsduur niet nadat er meer gegevens aan de tabel zijn toegevoegd, dus de update naar statistieken belemmert alleen de prestaties ervan. Laten we nu eens kijken wat er gebeurt als we de optie Statistieken automatisch bijwerken asynchroon inschakelen.

De test, versie 2

We beginnen met het terugzetten naar de back-up die ik heb gemaakt voordat we met de eerste test begonnen. Ik heb de opgeslagen procedure opnieuw gemaakt en vervolgens de database-optie gewijzigd om de statistieken asynchroon bij te werken:

GEBRUIK [master];GOALTER DATABASE [AdventureWorks2012_Big] STEL AUTO_UPDATE_STATISTICS_ASYNC IN MET NO_WAITGO

Ik startte de Extended Events-sessie en voerde de opgeslagen procedure opnieuw meerdere keren uit, met verschillende klant-ID's:

ALTER EVENT SESSIE [StatsUpdate_QueryPerf]OP SERVERSTATE =START;GA EXEC Sales.usp_GetCustomerStats11331, '2012-08-01 00:00:00.000', '2012-08-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11330, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11506, '2012-11-01 00:00:00.000', '2012-11-30 23 :59:59.997'GOEXEC Sales.usp_GetCustomerStats17061, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11711, '2013-03-01 00:00:00.000', '2013-03-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15131, '2013-02-01 00:00:00.000', '2013-02-28 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats29837, '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15750, '2013-03-01 00:00:00.000', '2013-03-31 23 :59:59.999'GO

Ik heb het aantal uitvoeringen en het plan geverifieerd door de procedurecache op te vragen:


Plancache:aan het begin, test 2


Queryplan voor opgeslagen procedure, met SQL Sentry Plan Explorer

Voor deze test is het plan gemaakt op 2014-04-08 21:15:55.490. Ik stopte de Extended Events-sessie en voegde opnieuw ongeveer 47 miljoen rijen met gegevens toe aan de tabel, met dezelfde query als voorheen.

Nadat de gegevens waren toegevoegd, controleerde ik de plancache om er zeker van te zijn dat er niets was veranderd en controleerde ik dat de statistieken nog niet waren bijgewerkt. Ten slotte startte ik de Extended Events-sessie opnieuw en voerde ik de opgeslagen procedure nog acht keer uit. Een laatste blik in de plancache toonde execution_count op 16 en een create_time van 2014-04-08 21:15:55.490. De execution_count en create_time laten zien dat de statistieken niet zijn bijgewerkt, omdat het plan nog niet uit de cache is gewist (als dat wel het geval was, zouden we een latere create_time en een uitvoeringsaantal van 8 hebben).


Plancache:na het laden van gegevens, test 2

Als we de Extended Events-uitvoer openen van na het laden van gegevens in SSMS, en opnieuw filteren zodat we alleen verklaringen van de opgeslagen procedure zien, evenals auto_stats-gebeurtenissen, vinden we dit (merk op dat de uitvoer is opgedeeld in twee schermafbeeldingen):


Uitvoer van uitgebreide gebeurtenissen:test 2, SP-uitvoering na laden van gegevens, deel I


Uitvoer van uitgebreide gebeurtenissen:test 2, SP-uitvoering na laden van gegevens, deel II

De gebeurtenissen voor de uitvoering van de eerste aanroep van de opgeslagen procedure zijn blauw gemarkeerd - ze beginnen op 2014-04-08 21:54:14.9480607 en er zijn zeven (7) gebeurtenissen. Houd er rekening mee dat er drie (3) auto_stats-gebeurtenissen zijn, maar geen van hen is echt voltooid, zoals we zagen toen de optie Statistieken automatisch bijwerken asynchroon was uitgeschakeld. Je zult merken dat de automatische update voor een van de statistieken vrijwel onmiddellijk start (2014-04-08 21:54:14.9481288), en bij drie gebeurtenissen staat de rode tekst 'Stat Update #1' ernaast. Die update van de statistieken eindigt op 2014-04-08 21:54:16.5392219, iets minder dan twee seconden nadat het is gestart, maar nadat alle andere uitvoeringen van de procedure zijn voltooid. Dit is de reden waarom de execution_count van sys.dm_exec_query_stats 16 toont. Uit de XE-uitvoer kunnen we zien dat de andere statistische updates dan voltooid zijn (Stat Update #2 en Stat Update #3). Alle updates zijn asynchroon met de uitvoering van de oorspronkelijke opgeslagen procedure.

Samenvatting

Zoals u kunt zien, kunnen automatische updates van statistieken de prestaties van zoekopdrachten negatief beïnvloeden. De mate van impact hangt af van de hoeveelheid gegevens die moet worden gelezen om de statistiek bij te werken, en van de systeembronnen. In sommige gevallen nemen de queryprestaties slechts met milliseconden toe en zijn ze hoogstwaarschijnlijk niet waarneembaar voor gebruikers. Andere keren kan de duur dramatisch toenemen, wat vervolgens de ervaring van de eindgebruiker beïnvloedt. In het geval dat het queryplan niet verandert na een update van statistieken, is het de moeite waard om de optie Statistieken automatisch bijwerken in te schakelen, om de impact op de queryprestaties te verminderen.


  1. SQL ORDER BY:De 5 do's en don'ts om gegevens als een professional te sorteren

  2. MIN/MAX vs BESTELLEN PER en LIMIT

  3. Waarvoorwaarde voor samengevoegde tabel in Sequelize ORM

  4. Door komma's gescheiden waarden naar IN-functie in orakel