Redan i april skrev jag om några inbyggda metoder inom SQL Server som kan användas för att spåra automatiska uppdateringar av statistik. De tre alternativen jag gav var SQL Trace, Extended Events och ögonblicksbilder av sys.dm_db_stats_properties. Även om dessa tre alternativ förblir genomförbara (även i SQL Server 2014, även om min bästa rekommendation fortfarande är XE), är ett ytterligare alternativ som jag märkte när jag körde några tester nyligen SQL Sentry Plan Explorer.
Många av er använder Plan Explorer bara för att läsa verkställande planer, vilket är bra. Det har många fördelar jämfört med Management Studio när det gäller att granska planer – från de små sakerna, som att kunna sortera på toppoperatörer och enkelt se problem med kardinalitetsberäkningar, till större fördelar, som att hantera komplexa och stora planer och att kunna välja en uttalande inom en batch för enklare plangranskning. Men bakom det visuella som gör det lättare att dissekera planer erbjuder Plan Explorer också möjligheten att köra en fråga och se den faktiska planen (istället för att köra den i Management Studio och spara den). Och utöver det, när du kör planen från PE, finns det ytterligare information som kan vara användbar.
Låt oss börja med demon som jag använde i mitt senaste inlägg, Hur automatiska uppdateringar av statistik kan påverka frågeprestanda. Jag började med databasen AdventureWorks2012 och jag skapade en kopia av tabellen SalesOrderHeader med över 200 miljoner rader. Tabellen har ett klustrat index på SalesOrderID och ett icke-klustrat index på CustomerID, OrderDate, SubTotal. [Återigen:om du ska göra upprepade tester, ta en säkerhetskopia av den här databasen nu för att spara lite tid.] Jag verifierade först det aktuella antalet rader i tabellen och antalet rader som skulle behöva ändras för att anropa en automatisk uppdatering:
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 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
Den lagrade proceduren som jag använder för att testa har redan skapats, men för fullständighetens skull listas koden nedan:
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
Tidigare har jag antingen startat en spårningssession eller en utökad händelsesession eller ställt in min metod för att ögonblicksbilda sys.dm_db_stats_properties till en tabell. För det här exemplet körde jag bara ovanstående lagrade procedur några gånger:
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
Jag kontrollerade sedan procedurens cache för att verifiera antalet exekveringar och verifierade även planen som cacheades:
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;
Plancache-information för SP:Vid start
Frågeplan för lagrad procedur med SQL Sentry Plan Explorer
Planen skapades 2014-09-29 23:23.01.
Därefter lade jag till 61 miljoner rader i tabellen för att ogiltigförklara den aktuella statistiken, och när infogningen var klar kontrollerade jag radantalet:
Big_SalesOrderHeader CIX och NCI Information:Efter infogning av 61 miljoner rader
Innan jag körde den lagrade proceduren igen, verifierade jag att antalet körningar inte hade ändrats, att creation_time fortfarande var 2014-09-29 23:23.01 för planen och att statistiken inte hade uppdaterats:
Planera cacheinformation för SP:direkt efter infogning
NCI-statistik:Efter infogning
Nu, i förra blogginlägget, körde jag uttalandet i Management Studio, men den här gången körde jag frågan direkt från Plan Explorer, och fångade den faktiska planen via PE (alternativet inringat i rött i bilden nedan).
Kör lagrad procedur från Plan Explorer
När du exekverar en sats från PE måste du ange instansen och databasen som du vill ansluta till, och sedan meddelas du att frågan kommer att köras och den faktiska planen kommer att returneras, men resultat kommer inte att returneras. Observera att detta är annorlunda än Management Studio, där du ser resultaten.
Efter att jag kört den lagrade proceduren får jag inte bara planen i utgången, utan jag ser även vilka uttalanden som kördes:
Planera Explorer-utdata efter körning SP (efter infogning)
Det här är ganska coolt ... förutom att se satsen exekveras i den lagrade proceduren, ser jag också uppdateringarna av statistik, precis som jag gjorde när jag fångat uppdateringar med Extended Events eller SQL Trace. Tillsammans med utförandets körning kan vi också se CPU, varaktighet och IO-information. Nu – varningen här är att jag kan se denna information om Jag kör uttalandet som anropar statistikuppdateringen från Plan Explorer. Det kommer förmodligen inte att hända ofta i din produktionsmiljö, men du kanske ser detta när du testar (för förhoppningsvis involverar din testning inte bara att köra SELECT-frågor, utan också involverar INSERT/UPDATE/DELETE-frågor precis som du skulle göra se i en normal arbetsbelastning). Men om du övervakar din miljö med ett verktyg som SQL Sentry, kan du se dessa uppdateringar i Top SQL så länge de överskrider tröskeln för Top SQL-samling. SQL Sentry har standardtrösklar som frågor måste överskrida innan de fångas upp som Top SQL (varaktigheten måste till exempel överstiga fem (5) sekunder), men du kan ändra dessa och lägga till andra trösklar som läsningar. I det här exemplet, endast i testsyfte , jag ändrade mitt tröskelvärde för min Top SQL minimivaraktighet till 10 millisekunder och mitt läströskel till 500, och SQL Sentry kunde fånga några av statistikuppdateringarna:
Statistikuppdateringar infångade av SQL Sentry
Som sagt, om övervakning kan fånga dessa händelser kommer i slutändan att bero på systemresurser och mängden data som måste läsas för att uppdatera statistiken. Dina statistikuppdateringar får inte överstiga dessa tröskelvärden, så du kan behöva göra mer proaktivt grävande för att hitta dem.
Sammanfattning
Jag uppmuntrar alltid DBA:er att proaktivt hantera statistik – vilket innebär att det finns ett jobb på plats för att uppdatera statistik på en regelbunden basis. Men även om det jobbet körs varje natt (vilket jag inte nödvändigtvis rekommenderar), är det fortfarande fullt möjligt att uppdateringar av statistik sker automatiskt under dagen, eftersom vissa tabeller är mer volatila än andra och har ett stort antal ändringar. Detta är inte onormalt, och beroende på storleken på tabellen och antalet ändringar, kanske de automatiska uppdateringarna inte stör användarnas frågor nämnvärt. Men det enda sättet att veta är att övervaka dessa uppdateringar – oavsett om du använder inbyggda verktyg eller verktyg från tredje part – så att du kan ligga steget före potentiella problem och åtgärda dem innan de eskalerar.