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

Un altro modo per visualizzare gli aggiornamenti automatici delle statistiche

Ad aprile ho scritto di alcuni metodi nativi all'interno di SQL Server che possono essere utilizzati per tenere traccia degli aggiornamenti automatici delle statistiche. Le tre opzioni che ho fornito sono SQL Trace, Extended Events e snapshot di sys.dm_db_stats_properties. Sebbene queste tre opzioni rimangano valide (anche in SQL Server 2014, sebbene il mio consiglio principale sia ancora XE), un'opzione aggiuntiva che ho notato durante l'esecuzione di alcuni test di recente è SQL Sentry Plan Explorer.

Molti di voi usano Plan Explorer semplicemente per leggere i piani in esecuzione, il che è fantastico. Offre numerosi vantaggi rispetto a Management Studio quando si tratta di rivedere i piani, dalle piccole cose, come essere in grado di ordinare i migliori operatori e vedere facilmente i problemi di stima della cardinalità, a vantaggi più grandi, come la gestione di piani complessi e di grandi dimensioni e la possibilità di selezionarne uno dichiarazione all'interno di un batch per una più facile revisione del piano. Ma dietro gli elementi visivi che semplificano l'analisi dei piani, Plan Explorer offre anche la possibilità di eseguire una query e visualizzare il piano effettivo (piuttosto che eseguirlo in Management Studio e salvarlo). Inoltre, quando esegui il piano da PE, vengono acquisite informazioni aggiuntive che possono essere utili.

Iniziamo con la demo che ho utilizzato nel mio recente post, Come gli aggiornamenti automatici delle statistiche possono influire sulle prestazioni delle query. Ho iniziato con il database AdventureWorks2012 e ho creato una copia della tabella SalesOrderHeader con oltre 200 milioni di righe. La tabella ha un indice cluster su SalesOrderID e un indice non cluster su CustomerID, OrderDate, SubTotal. [Di nuovo:se hai intenzione di eseguire test ripetuti, fai un backup di questo database a questo punto per risparmiare tempo.] Ho prima verificato il numero corrente di righe nella tabella e il numero di righe che dovrebbero essere modificate per richiamare un aggiornamento automatico:

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');


Informazioni Big_SalesOrderHeader CIX e NCI

Ho anche verificato l'intestazione delle statistiche correnti per l'indice:

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


Statistiche NCI:all'inizio

La stored procedure che utilizzo per il test è già stata creata, ma per completezza il codice è riportato di seguito:

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

In precedenza, avviavo una sessione Trace o Extended Events oppure impostavo il mio metodo per eseguire lo snapshot di sys.dm_db_stats_properties su una tabella. Per questo esempio, ho appena eseguito la procedura memorizzata sopra alcune volte:

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

Ho quindi controllato la cache delle procedure per verificare il conteggio delle esecuzioni e ho anche verificato il piano memorizzato nella 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;


Informazioni sulla cache del piano per l'SP:all'inizio


Piano di query per stored procedure, utilizzando SQL Sentry Plan Explorer

Il piano è stato creato il 29-09-2014 alle 23:23.01.

Successivamente ho aggiunto 61 milioni di righe alla tabella per invalidare le statistiche correnti e, una volta completato l'inserimento, ho controllato il conteggio delle righe:


Big_SalesOrderHeader Informazioni CIX e NCI:dopo l'inserimento di 61 milioni righe

Prima di eseguire nuovamente la procedura memorizzata, ho verificato che il conteggio delle esecuzioni non fosse cambiato, che il tempo di creazione fosse ancora 2014-09-29 23:23.01 per il piano e che le statistiche non fossero state aggiornate:


Informazioni sulla cache del piano per l'SP:immediatamente dopo l'inserimento


Statistiche NCI:dopo l'inserimento

Ora, nel precedente post del blog, ho eseguito la dichiarazione in Management Studio, ma questa volta ho eseguito la query direttamente da Plan Explorer e ho acquisito il piano effettivo tramite PE (opzione cerchiata in rosso nell'immagine sotto).


Esegui stored procedure da Plan Explorer

Quando esegui un'istruzione da PE, devi inserire l'istanza e il database a cui desideri connetterti, quindi ti viene notificato che la query verrà eseguita e il piano effettivo verrà restituito, ma i risultati non verranno restituiti. Nota che questo è diverso da Management Studio, dove vedi i risultati.

Dopo aver eseguito la procedura memorizzata, nell'output non solo ottengo il piano, ma vedo quali istruzioni sono state eseguite:


Output Plan Explorer dopo l'esecuzione SP (dopo l'inserimento)

Questo è piuttosto interessante... oltre a vedere l'istruzione eseguita nella stored procedure, vedo anche gli aggiornamenti delle statistiche, proprio come ho fatto quando ho acquisito gli aggiornamenti utilizzando gli eventi estesi o SQL Trace. Insieme all'esecuzione dell'istruzione, possiamo anche vedere le informazioni su CPU, durata e IO. Ora, l'avvertenza qui è che posso vedere queste informazioni se Eseguo l'istruzione che richiama l'aggiornamento delle statistiche da Plan Explorer. Questo probabilmente non accadrà spesso nel tuo ambiente di produzione, ma potresti vederlo quando esegui i test (perché si spera che i tuoi test non riguardino solo l'esecuzione di query SELECT, ma coinvolgano anche query INSERT/UPDATE/DELETE proprio come faresti vedere in un normale carico di lavoro). Tuttavia, se stai monitorando il tuo ambiente con uno strumento come SQL Sentry, potresti vedere questi aggiornamenti in Top SQL purché superino la soglia di raccolta Top SQL. SQL Sentry ha soglie predefinite che le query devono superare prima di essere acquisite come SQL principale (ad es. la durata deve superare i cinque (5) secondi), ma è possibile modificarle e aggiungere altre soglie come le letture. In questo esempio, solo a scopo di test , ho modificato la soglia di durata minima di SQL superiore a 10 millisecondi e la soglia di lettura a 500 e SQL Sentry è stato in grado di acquisire alcuni degli aggiornamenti delle statistiche:


Aggiornamenti delle statistiche acquisiti da SQL Sentry

Detto questo, se il monitoraggio può acquisire questi eventi dipenderà in definitiva dalle risorse di sistema e dalla quantità di dati che devono essere letti per aggiornare la statistica. Gli aggiornamenti delle tue statistiche potrebbero non superare queste soglie, quindi potresti dover eseguire ricerche più proattive per trovarli.

Riepilogo

Incoraggio sempre i DBA a gestire le statistiche in modo proattivo, il che significa che è in atto un lavoro per aggiornare le statistiche su base regolare. Tuttavia, anche se quel lavoro viene eseguito ogni notte (cosa che non sto necessariamente consigliando), è comunque possibile che gli aggiornamenti delle statistiche avvengano automaticamente durante il giorno, perché alcune tabelle sono più volatili di altre e hanno un numero elevato di modifiche. Questo non è anomalo e, a seconda delle dimensioni della tabella e della quantità di modifiche, gli aggiornamenti automatici potrebbero non interferire in modo significativo con le query degli utenti. Ma l'unico modo per saperlo è monitorare quegli aggiornamenti – indipendentemente dal fatto che tu stia utilizzando strumenti nativi o di terze parti, in modo da poter anticipare potenziali problemi e risolverli prima che si intensifichino.