Database
 sql >> Datenbank >  >> RDS >> Database

Eine weitere Möglichkeit, automatische Aktualisierungen von Statistiken anzuzeigen

Bereits im April habe ich über einige native Methoden in SQL Server geschrieben, die verwendet werden können, um automatische Aktualisierungen von Statistiken zu verfolgen. Die drei von mir bereitgestellten Optionen waren SQL Trace, Extended Events und Snapshots von sys.dm_db_stats_properties. Während diese drei Optionen praktikabel bleiben (selbst in SQL Server 2014, obwohl meine Top-Empfehlung immer noch XE ist), ist eine zusätzliche Option, die mir beim Ausführen einiger Tests kürzlich aufgefallen ist, der SQL Sentry Plan Explorer.

Viele von Ihnen verwenden Plan Explorer einfach zum Lesen von Ausführungsplänen, was großartig ist. Es hat zahlreiche Vorteile gegenüber Management Studio, wenn es um die Überprüfung von Plänen geht – von kleinen Dingen, wie der Möglichkeit, nach Top-Operatoren zu sortieren und Probleme mit der Kardinalitätsschätzung leicht zu erkennen, bis hin zu größeren Vorteilen, wie der Handhabung komplexer und großer Pläne und der Möglichkeit, einen auszuwählen Anweisung innerhalb eines Stapels für eine einfachere Planüberprüfung. Aber hinter den visuellen Elementen, die das Analysieren von Plänen erleichtern, bietet Plan Explorer auch die Möglichkeit, eine Abfrage auszuführen und den tatsächlichen Plan anzuzeigen (anstatt ihn in Management Studio auszuführen und zu speichern). Darüber hinaus werden beim Ausführen des Plans von PE zusätzliche Informationen erfasst, die nützlich sein können.

Beginnen wir mit der Demo, die ich in meinem letzten Beitrag „How Automatic Updates to Statistics Can Impact Query Performance“ verwendet habe. Ich habe mit der AdventureWorks2012-Datenbank begonnen und eine Kopie der SalesOrderHeader-Tabelle mit über 200 Millionen Zeilen erstellt. Die Tabelle hat einen Clustered-Index für SalesOrderID und einen Nonclustered-Index für CustomerID, OrderDate, SubTotal. [Auch hier:Wenn Sie wiederholte Tests durchführen, erstellen Sie an dieser Stelle eine Sicherungskopie dieser Datenbank, um Zeit zu sparen.] Ich habe zuerst die aktuelle Anzahl der Zeilen in der Tabelle und die Anzahl der Zeilen, die geändert werden müssten, überprüft So rufen Sie ein automatisches Update auf:

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- und NCI-Informationen

Ich habe auch den aktuellen Statistik-Header für den Index überprüft:

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


NCI-Statistiken:Zu Beginn

Die gespeicherte Prozedur, die ich zum Testen verwende, wurde bereits erstellt, aber der Vollständigkeit halber ist der Code unten aufgeführt:

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

Zuvor habe ich entweder eine Trace- oder Extended Events-Sitzung gestartet oder meine Methode eingerichtet, um einen Snapshot von sys.dm_db_stats_properties in eine Tabelle zu erstellen. Für dieses Beispiel habe ich die obige gespeicherte Prozedur nur ein paar Mal ausgeführt:

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

Ich habe dann den Prozedur-Cache überprüft, um die Ausführungsanzahl zu überprüfen, und auch den Plan überprüft, der zwischengespeichert wurde:

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;


Planen Sie Cache-Informationen für den SP:Beim Start


Abfrageplan für gespeicherte Prozeduren mit SQL Sentry Plan Explorer

Der Plan wurde am 29.09.2014 um 23:23.01 erstellt.

Als nächstes fügte ich der Tabelle 61 Millionen Zeilen hinzu, um die aktuellen Statistiken ungültig zu machen, und nachdem die Einfügung abgeschlossen war, überprüfte ich die Anzahl der Zeilen:


Big_SalesOrderHeader CIX- und NCI-Informationen:Nach Einfügung von 61 Millionen Zeilen

Bevor ich die gespeicherte Prozedur erneut ausführte, überprüfte ich, dass sich die Ausführungsanzahl nicht geändert hatte, dass die creation_time für den Plan immer noch 2014-09-29 23:23.01 war und dass die Statistiken nicht aktualisiert wurden:


Planen Sie Cache-Informationen für den SP:Unmittelbar nach dem Einfügen


NCI-Statistiken:Nach dem Einfügen

Nun, im vorherigen Blogbeitrag habe ich die Anweisung in Management Studio ausgeführt, aber dieses Mal habe ich die Abfrage direkt aus dem Plan Explorer ausgeführt und den tatsächlichen Plan über PE erfasst (Option im Bild unten rot eingekreist).


Gespeicherte Prozedur aus dem Plan-Explorer ausführen

Wenn Sie eine Anweisung von PE ausführen, müssen Sie die Instanz und die Datenbank eingeben, zu der Sie eine Verbindung herstellen möchten, und dann werden Sie benachrichtigt, dass die Abfrage ausgeführt und der tatsächliche Plan zurückgegeben wird, aber keine Ergebnisse zurückgegeben werden. Beachten Sie, dass dies anders ist als in Management Studio, wo Sie die Ergebnisse sehen.

Nachdem ich die gespeicherte Prozedur ausgeführt habe, erhalte ich in der Ausgabe nicht nur den Plan, sondern sehe auch, welche Anweisungen ausgeführt wurden:


Plan Explorer-Ausgabe nach Ausführung SP (nach Einfügung)

Das ist ziemlich cool … zusätzlich zur Ausführung der Anweisung in der gespeicherten Prozedur sehe ich auch die Aktualisierungen der Statistiken, genau wie ich es getan habe, als ich Aktualisierungen mit Extended Events oder SQL Trace erfasst habe. Neben der Anweisungsausführung können wir auch CPU-, Dauer- und E/A-Informationen sehen. Nun – der Vorbehalt hier ist, dass ich diese Informationen wenn sehen kann Ich führe die Anweisung aus, die die Statistikaktualisierung aus dem Plan-Explorer aufruft. Das wird in Ihrer Produktionsumgebung wahrscheinlich nicht oft vorkommen, aber Sie können dies sehen, wenn Sie Tests durchführen (weil Ihre Tests hoffentlich nicht nur das Ausführen von SELECT-Abfragen umfassen, sondern auch INSERT/UPDATE/DELETE-Abfragen, genau wie Sie es tun würden siehe bei normaler Auslastung). Wenn Sie Ihre Umgebung jedoch mit einem Tool wie SQL Sentry überwachen, werden Ihnen diese Aktualisierungen möglicherweise in Top SQL angezeigt, solange sie den Schwellenwert für die Top-SQL-Erfassung überschreiten. SQL Sentry verfügt über Standardschwellenwerte, die Abfragen überschreiten müssen, bevor sie als Top-SQL erfasst werden (z. B. muss die Dauer fünf (5) Sekunden überschreiten), aber Sie können diese ändern und andere Schwellenwerte wie Lesevorgänge hinzufügen. In diesem Beispiel nur zu Testzwecken , habe ich meinen Schwellenwert für die Mindestdauer von Top SQL auf 10 Millisekunden und meinen Schwellenwert für Lesevorgänge auf 500 geändert, und SQL Sentry konnte einige der Statistikaktualisierungen erfassen:


Von SQL Sentry erfasste Statistikaktualisierungen

Ob die Überwachung diese Ereignisse erfassen kann, hängt jedoch letztendlich von den Systemressourcen und der Datenmenge ab, die gelesen werden muss, um die Statistik zu aktualisieren. Ihre Statistikaktualisierungen dürfen diese Schwellenwerte nicht überschreiten, daher müssen Sie möglicherweise proaktiver suchen, um sie zu finden.

Zusammenfassung

Ich ermutige DBAs immer dazu, Statistiken proaktiv zu verwalten – was bedeutet, dass es eine Aufgabe gibt, Statistiken regelmäßig zu aktualisieren. Aber selbst wenn dieser Job jede Nacht läuft (was ich nicht unbedingt empfehle), ist es immer noch möglich, dass Statistiken automatisch den ganzen Tag über aktualisiert werden, da einige Tabellen volatiler sind als andere und eine hohe Anzahl von Änderungen aufweisen. Dies ist nicht ungewöhnlich, und abhängig von der Größe der Tabelle und der Anzahl der Änderungen beeinträchtigen die automatischen Updates die Benutzerabfragen möglicherweise nicht wesentlich. Die einzige Möglichkeit, dies herauszufinden, besteht darin, diese Aktualisierungen zu überwachen – egal, ob Sie native Tools oder Tools von Drittanbietern verwenden – damit Sie potenziellen Problemen immer einen Schritt voraus sind und sie beheben können, bevor sie eskalieren.