Tilbage i april skrev jeg om nogle native metoder inden for SQL Server, der kan bruges til at spore automatiske opdateringer til statistik. De tre muligheder, jeg gav, var SQL Trace, Extended Events og snapshots af sys.dm_db_stats_properties. Selvom disse tre muligheder forbliver levedygtige (selv i SQL Server 2014, selvom min bedste anbefaling stadig er XE), er en ekstra mulighed, jeg bemærkede, da jeg kørte nogle tests for nylig, SQL Sentry Plan Explorer.
Mange af jer bruger Plan Explorer blot til at læse eksekveringsplaner, hvilket er fantastisk. Det har adskillige fordele i forhold til Management Studio, når det kommer til at gennemgå planer - fra de små ting, som at kunne sortere på topoperatører og nemt se problemer med kardinalitetsestimater, til større fordele, som at håndtere komplekse og store planer og at kunne vælge en erklæring inden for en batch for lettere plangennemgang. Men bag det visuelle, der gør det lettere at dissekere planer, tilbyder Plan Explorer også muligheden for at udføre en forespørgsel og se den faktiske plan (i stedet for at køre den i Management Studio og gemme den). Og oven i det, når du kører planen fra PE, er der yderligere oplysninger, som kan være nyttige.
Lad os starte med demoen, som jeg brugte i mit seneste indlæg, Hvordan automatiske opdateringer til statistik kan påvirke forespørgselsydeevne. Jeg startede med AdventureWorks2012-databasen, og jeg lavede en kopi af SalesOrderHeader-tabellen med over 200 millioner rækker. Tabellen har et klynget indeks på SalesOrderID og et ikke-clusteret indeks på CustomerID, OrderDate, SubTotal. [Igen:hvis du skal lave gentagne tests, skal du tage en sikkerhedskopi af denne database på dette tidspunkt for at spare dig selv for lidt tid.] Jeg bekræftede først det aktuelle antal rækker i tabellen og antallet af rækker, der skulle ændres for at påkalde en automatisk opdatering:
SELECT OBJECT_NAME([p].[object_id]) [TableName], [si].[name] [IndexName], [au].[type_desc] [Type], [p].[rows] [RowCount], ([p].[rows]*.20) + 500 [UpdateThreshold], [au].total_pages [PageCount], (([au].[total_pages]*8)/1024)/1024 [TotalGB] FROM [sys].[partitions] [p] JOIN [sys].[allocation_units] [au] ON [p].[partition_id] = [au].[container_id] JOIN [sys].[indexes] [si] on [p].[object_id] = [si].object_id and [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
Den lagrede procedure, som jeg bruger til at teste, var allerede oprettet, men for fuldstændighedens skyld er koden angivet nedenfor:
CREATE PROCEDURE Sales.usp_GetCustomerStats @CustomerID INT, @StartDate DATETIME, @EndDate DATETIME AS BEGIN SET NOCOUNT ON; SELECT CustomerID, DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate), COUNT([SalesOrderID]) as Computed FROM [Sales].[Big_SalesOrderHeader] WHERE CustomerID = @CustomerID AND OrderDate BETWEEN @StartDate and @EndDate GROUP BY CustomerID, DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate) ORDER BY DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate); END
Tidligere startede jeg enten en Trace- eller Extended Events-session eller konfigurerede min metode til at snapshotte sys.dm_db_stats_properties til en tabel. For dette eksempel har jeg lige kørt ovenstående lagrede procedure et par gange:
EXEC Sales.usp_GetCustomerStats 11331, '2012-08-01 00:00:00.000', '2012-08-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 11330, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 11506, '2012-11-01 00:00:00.000', '2012-11-30 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 17061, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 11711, '2013-03-01 00:00:00.000', '2013-03-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 15131, '2013-02-01 00:00:00.000', '2013-02-28 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 29837, '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 15750, '2013-03-01 00:00:00.000', '2013-03-31 23:59:59.997' GO
Jeg tjekkede derefter procedurecachen for at bekræfte antallet af eksekveringer og bekræftede også planen, der var cache:
SELECT OBJECT_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] WHERE [st].[text] LIKE '%usp_GetCustomerStats%' AND OBJECT_NAME([st].[objectid]) IS NOT NULL;
Plan-cache-info for SP:Ved start
Forespørgselsplan for lagret procedure ved hjælp af SQL Sentry Plan Explorer
Planen blev oprettet 2014-09-29 23:23.01.
Dernæst tilføjede jeg 61 millioner rækker til tabellen for at ugyldiggøre den aktuelle statistik, og når indsættelsen var fuldført, tjekkede jeg rækkeantallet:
Big_SalesOrderHeader CIX og NCI-oplysninger:Efter indsættelse af 61 mio. rækker
Før jeg kørte den lagrede procedure igen, bekræftede jeg, at eksekveringsantallet ikke var ændret, at oprettelsestidspunktet stadig var 2014-09-29 23:23.01 for planen, og at statistikken ikke var opdateret:
Planlægge cacheoplysninger for SP:Umiddelbart efter indsættelse
NCI-statistik:Efter indsættelse
Nu, i det forrige blogindlæg, kørte jeg erklæringen i Management Studio, men denne gang kørte jeg forespørgslen direkte fra Plan Explorer og fangede den faktiske plan via PE (indstillingen cirklet med rødt på billedet nedenfor).
Udfør lagret procedure fra Plan Explorer
Når du udfører en sætning fra PE, skal du indtaste den instans og database, du vil oprette forbindelse til, og så får du besked om, at forespørgslen kører, og den faktiske plan vil blive returneret, men resultaterne vil ikke blive returneret. Bemærk, at dette er anderledes end Management Studio, hvor du kan se resultaterne.
Efter at jeg kørte den lagrede procedure, får jeg i outputtet ikke kun planen, men jeg kan også se, hvilke udsagn der blev udført:
Plan Explorer-output efter udførelse af SP (efter indsættelse)
Det er ret fedt...udover at se sætningen eksekveret i den lagrede procedure, ser jeg også opdateringerne til statistik, ligesom jeg gjorde, da jeg fangede opdateringer ved hjælp af Extended Events eller SQL Trace. Sammen med sætningsudførelsen kan vi også se CPU, varighed og IO-oplysninger. Nu – forbeholdet her er, at jeg kan se denne information hvis Jeg kører erklæringen, der påberåber sig statistikopdateringen fra Plan Explorer. Det vil sandsynligvis ikke ske ofte i dit produktionsmiljø, men du kan se dette, når du tester (fordi forhåbentlig involverer din testning ikke kun at køre SELECT-forespørgsler, men involverer også INSERT/OPDATERE/SLET-forespørgsler ligesom du ville se i en normal arbejdsbyrde). Men hvis du overvåger dit miljø med et værktøj som SQL Sentry, kan du muligvis se disse opdateringer i Top SQL så længe de overskrider Top SQL-indsamlingstærsklen. SQL Sentry har standardtærskler, som forespørgsler skal overskride, før de fanges som Top SQL (varigheden skal f.eks. overstige fem (5) sekunder), men du kan ændre dem og tilføje andre tærskler, såsom læsninger. I dette eksempel kun til testformål , jeg ændrede min Top SQL minimum varighedstærskel til 10 millisekunder og min læsetærskel til 500, og SQL Sentry var i stand til at fange nogle af statistikopdateringerne:
Statistikopdateringer fanget af SQL Sentry
Når det er sagt, om overvågning kan fange disse hændelser vil i sidste ende afhænge af systemressourcer og mængden af data, der skal læses for at opdatere statistikken. Dine statistikopdateringer må ikke overskride disse tærskler, så du skal muligvis foretage mere proaktiv undersøgelse for at finde dem.
Oversigt
Jeg opfordrer altid DBA'er til proaktivt at styre statistik - hvilket betyder, at der er et job på plads for at opdatere statistik løbende. Men selvom det job kører hver nat (hvilket jeg ikke nødvendigvis anbefaler), er det stadig meget muligt, at opdateringer til statistik sker automatisk i løbet af dagen, fordi nogle tabeller er mere volatile end andre og har et stort antal ændringer. Dette er ikke unormalt, og afhængigt af tabellens størrelse og mængden af ændringer, vil de automatiske opdateringer muligvis ikke forstyrre brugerforespørgsler væsentligt. Men den eneste måde at vide det på er at overvåge disse opdateringer – uanset om du bruger indbyggede værktøjer eller tredjepartsværktøjer – så du kan være på forkant med potentielle problemer og løse dem, før de eskalerer.