sql >> Base de Datos >  >> RDS >> Database

Otra forma de ver las actualizaciones automáticas de las estadísticas

En abril escribí sobre algunos métodos nativos dentro de SQL Server que se pueden usar para rastrear actualizaciones automáticas de estadísticas. Las tres opciones que proporcioné fueron seguimiento de SQL, eventos extendidos e instantáneas de sys.dm_db_stats_properties. Si bien estas tres opciones siguen siendo viables (incluso en SQL Server 2014, aunque mi principal recomendación sigue siendo XE), una opción adicional que noté al ejecutar algunas pruebas recientemente es SQL Sentry Plan Explorer.

Muchos de ustedes usan Plan Explorer simplemente para leer planes de ejecución, lo cual es genial. Tiene numerosos beneficios sobre Management Studio cuando se trata de revisar planes, desde las pequeñas cosas, como poder clasificar a los principales operadores y ver fácilmente los problemas de estimación de cardinalidad, hasta beneficios más grandes, como manejar planes grandes y complejos y poder seleccionar uno. declaración dentro de un lote para facilitar la revisión del plan. Pero detrás de las imágenes que facilitan la disección de planes, Plan Explorer también ofrece la capacidad de ejecutar una consulta y ver el plan real (en lugar de ejecutarlo en Management Studio y guardarlo). Y además de eso, cuando ejecuta el plan desde PE, se captura información adicional que puede ser útil.

Comencemos con la demostración que utilicé en mi publicación reciente, Cómo las actualizaciones automáticas de las estadísticas pueden afectar el rendimiento de las consultas. Empecé con la base de datos AdventureWorks2012 y creé una copia de la tabla SalesOrderHeader con más de 200 millones de filas. La tabla tiene un índice agrupado en SalesOrderID y un índice no agrupado en CustomerID, OrderDate, SubTotal. [Otra vez:si va a realizar pruebas repetidas, haga una copia de seguridad de esta base de datos en este punto para ahorrar tiempo.] Primero verifiqué la cantidad actual de filas en la tabla y la cantidad de filas que necesitarían cambiar para invocar una actualización automática:

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 Información de CIX y NCI

También verifiqué el encabezado de estadísticas actual para el índice:

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


Estadísticas del NCI:al inicio

El procedimiento almacenado que utilizo para las pruebas ya se creó, pero para completar el código se muestra a continuación:

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

Anteriormente, comencé una sesión de seguimiento o eventos extendidos, o configuré mi método para tomar una instantánea de sys.dm_db_stats_properties en una tabla. Para este ejemplo, acabo de ejecutar el procedimiento almacenado anterior varias veces:

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

Luego revisé el caché de procedimientos para verificar el conteo de ejecución y también verifiqué el plan que estaba en caché:

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;


Información de caché del plan para el SP:al inicio


Plan de consultas para procedimientos almacenados, utilizando SQL Sentry Plan Explorer

El plan se creó el 2014-09-29 23:23.01.

A continuación, agregué 61 millones de filas a la tabla para invalidar las estadísticas actuales y, una vez que se completó la inserción, verifiqué el recuento de filas:


Big_SalesOrderHeader Información de CIX y NCI:después de la inserción de 61 millones filas

Antes de volver a ejecutar el procedimiento almacenado, verifiqué que el recuento de ejecución no había cambiado, que el tiempo de creación todavía era 2014-09-29 23:23.01 para el plan y que las estadísticas no se habían actualizado:


Información de caché del plan para el SP:Inmediatamente después de insertar


Estadísticas del NCI:después de insertar

Ahora, en la publicación de blog anterior, ejecuté la declaración en Management Studio, pero esta vez ejecuté la consulta directamente desde Plan Explorer y capturé el Plan real a través de PE (opción marcada con un círculo rojo en la imagen a continuación).


Ejecutar procedimiento almacenado desde Plan Explorer

Cuando ejecuta una declaración de PE, debe ingresar la instancia y la base de datos a la que desea conectarse, y luego se le notifica que se ejecutará la consulta y se devolverá el plan real, pero no se devolverán los resultados. Tenga en cuenta que esto es diferente a Management Studio, donde sí ve los resultados.

Después de ejecutar el procedimiento almacenado, en la salida no solo obtengo el plan, sino que veo qué declaraciones se ejecutaron:


Salida del Explorador de planes después de la ejecución SP (después de la inserción)

Esto es genial... además de ver la declaración ejecutada en el procedimiento almacenado, también veo las actualizaciones de las estadísticas, tal como lo hice cuando capturé las actualizaciones usando Extended Events o SQL Trace. Junto con la ejecución de la declaración, también podemos ver información de CPU, duración y IO. Ahora, la advertencia aquí es que puedo ver esta información si Ejecuto la declaración que invoca la actualización de estadísticas de Plan Explorer. Eso probablemente no sucederá a menudo en su entorno de producción, pero puede ver esto cuando esté realizando pruebas (porque, con suerte, sus pruebas no solo implican ejecutar consultas SELECCIONAR, sino también consultas INSERTAR/ACTUALIZAR/ELIMINAR como lo haría ver en una carga de trabajo normal). Sin embargo, si supervisa su entorno con una herramienta como SQL Sentry, es posible que vea estas actualizaciones en Top SQL siempre que superen el umbral de recopilación de Top SQL. SQL Sentry tiene umbrales predeterminados que las consultas deben superar antes de que se capturen como Top SQL (por ejemplo, la duración debe superar los cinco (5) segundos), pero puede cambiarlos y agregar otros umbrales, como lecturas. En este ejemplo, solo con fines de prueba , cambié mi umbral de duración mínima de Top SQL a 10 milisegundos y mi umbral de lectura a 500, y SQL Sentry pudo capturar algunas de las actualizaciones de estadísticas:


Actualizaciones de estadísticas capturadas por SQL Sentry

Dicho esto, si el monitoreo puede capturar estos eventos dependerá en última instancia de los recursos del sistema y la cantidad de datos que deben leerse para actualizar la estadística. Es posible que las actualizaciones de sus estadísticas no excedan estos umbrales, por lo que es posible que deba realizar una investigación más proactiva para encontrarlas.

Resumen

Siempre animo a los DBA a administrar las estadísticas de manera proactiva, lo que significa que existe un trabajo para actualizar las estadísticas de forma regular. Sin embargo, incluso si ese trabajo se ejecuta todas las noches (lo cual no estoy recomendando necesariamente), es muy posible que las actualizaciones de las estadísticas ocurran automáticamente durante el día, porque algunas tablas son más volátiles que otras y tienen una gran cantidad de modificaciones. Esto no es anormal y, según el tamaño de la tabla y la cantidad de modificaciones, es posible que las actualizaciones automáticas no interfieran significativamente con las consultas de los usuarios. Pero la única forma de saberlo es monitorear esas actualizaciones – ya sea que esté utilizando herramientas nativas o herramientas de terceros – para que pueda adelantarse a posibles problemas y abordarlos antes de que se agraven.