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

Comprensión de lo que realmente actualiza sp_updatestats

Cuando estuve en Chicago hace unas semanas para uno de nuestros eventos de inmersión, un asistente tenía una pregunta sobre estadísticas. No entraré en todos los detalles sobre el problema, pero el asistente mencionó que las estadísticas se actualizaron usando sp_updatestats . Este es un método para actualizar estadísticas que nunca he recomendado; Siempre he recomendado una combinación de reconstrucción de índices y UPDATE STATISTICS para mantener las estadísticas actualizadas. Si no está familiarizado con sp_updatestats , es un comando que se ejecuta para que toda la base de datos actualice las estadísticas. Pero como Kimberly señaló al asistente, sp_updatestats actualizará una estadística siempre que se haya modificado una fila. Vaya Inmediatamente abrí Libros en línea y para sp_updatestats verás esto:

sp_updatestats actualiza solo las estadísticas que requieren actualización según la información de rowmodctr en la vista de catálogo sys.sysindexes, evitando así actualizaciones innecesarias de estadísticas en filas sin cambios

Ahora, lo admito, hice una suposición sobre lo que significaba "... requieren actualización basada en la información de rowmodctr en la vista de catálogo sys.sysindexes...". Supuse que la decisión de actualización seguiría la misma lógica que sigue la opción Actualizar estadísticas automáticamente, que es:

  • El tamaño de la tabla ha pasado de 0 a>0 filas (prueba 1).
  • El número de filas en la tabla cuando se recopilaron las estadísticas era de 500 o menos, y el colmodctr de la columna principal del objeto de estadísticas ha cambiado en más de 500 desde entonces (prueba 2).
  • La tabla tenía más de 500 filas cuando se recopilaron las estadísticas, y el colmodctr de la columna principal del objeto de estadísticas cambió en más de 500 + 20 % del número de filas de la tabla cuando se recopilaron las estadísticas ( prueba 3).

Esta lógica no se sigue para sp_updatestats . De hecho, la lógica es tan increíblemente simple que da miedo:si se modifica una fila, la estadística se actualiza. Una fila. UNA FILA. ¿Cuál es mi preocupación? Me preocupa la sobrecarga de actualizar estadísticas para un montón de estadísticas que realmente no necesitan actualizarse. Echemos un vistazo más de cerca a sp_updatestats .

Comenzaremos con una copia nueva de la base de datos AdventureWorks2012 que puede descargar desde Codeplex. Primero voy a actualizar filas en tres tablas diferentes:

USE [AdventureWorks2012];
GO
SET NOCOUNT ON;
GO
 
UPDATE [Production].[Product]
SET [Name] = 'Bike Chain'
WHERE [ProductID] = 952;
 
UPDATE [Person].[Person]
SET [LastName] = 'Cameron'
WHERE [LastName] = 'Diaz';
GO
 
INSERT INTO Sales.SalesReason
(Name, ReasonType, ModifiedDate)
VALUES('Stats', 'Test', GETDATE());
GO 10000

Modificamos una fila en Production.Product , 211 filas en Person.Person y agregamos 10,000 filas a Sales.SalesReason . Si el sp_updatestats El procedimiento siguió la misma lógica para las actualizaciones que la opción Actualización automática de estadísticas, luego solo Sales.SalesReason se actualizaría porque tenía 10 filas para comenzar (mientras que las 211 filas se actualizaron en Person.Person representan alrededor del uno por ciento de la tabla). Sin embargo, si profundizamos en sp_updatestats , podemos ver que la lógica utilizada es diferente. Tenga en cuenta que solo estoy extrayendo las declaraciones desde dentro de sp_updatestats que se utilizan para determinar qué estadísticas se actualizan.

Un cursor itera a través de todas las tablas definidas por el usuario y tablas internas en la base de datos:

declare ms_crs_tnames cursor local fast_forward read_only for
select name, object_id, schema_id, type from sys.objects o
where o.type = 'U' or o.type = 'IT'
open ms_crs_tnames
fetch next from ms_crs_tnames into @table_name, @table_id, @sch_id, @table_type

Otro cursor recorre las estadísticas de cada tabla y excluye montones e índices y estadísticas hipotéticos. Tenga en cuenta que sys.sysindexes se usa en sp_helpstats . Sysindexes es una tabla del sistema de SQL Server 2000 y está programada para eliminarse en una versión futura de SQL Server. Esto es interesante, ya que el otro método para determinar las filas actualizadas es sys.dm_db_stats_properties DMF, que solo está disponible en SQL 2008 R2 SP2 y SQL 2012 SP1.

set @index_names = cursor local fast_forward read_only for
select name, indid, rowmodctr
from sys.sysindexes
where id = @table_id
and indid > 0
and indexproperty(id, name, 'ishypothetical') = 0
order by indid

Después de un poco de preparación y lógica adicional, llegamos a un IF declaración que revela que sp_updatestats filtra las estadísticas que no han tenido filas actualizadas... confirmando que incluso si solo se ha modificado una fila, la estadística se actualizará. También hay una verificación para @is_ver_current , que está determinado por una función interna incorporada.

if ((@ind_rowmodctr <> 0) or ((@is_ver_current is not null) and (@is_ver_current = 0)))

Un par de comprobaciones más relacionadas con el muestreo y el nivel de compatibilidad, y luego UPDATE se ejecuta para la estadística. Antes de ejecutar sp_updatestats, podemos consultar sys.sysindexes para ver qué estadísticas se actualizarán:

SELECT [o].[name], [si].[indid], [si].[name], [si].[rowmodctr], [si].[rowcnt], [o].[type]
FROM [sys].[objects] [o]
JOIN [sys].[sysindexes] [si] ON [o].[object_id] = [si].[id]
WHERE ([o].[type] = 'U' OR [o].[type] = 'IT')
AND [si].[indid] > 0
AND [si].[rowmodctr] <> 0
ORDER BY [o].[type] DESC, [o].[name];

Además de las tres tablas que modificamos, hay otra estadística para una tabla de usuario (dbo.DatabaseLog ) y tres estadísticas internas que se actualizarán:


Estadísticas que se actualizarán

Si ejecutamos sp_updatestats para la base de datos AdventureWorks, el resultado enumera todas las tablas y las estadísticas actualizadas. El siguiente resultado se modifica para mostrar solo estadísticas actualizadas:

Actualizando [sys].[fulltext_avdl_1589580701]
[clust] ha sido actualizado...
1 índice(s)/estadística(s) han sido actualizados, 0 no requirió actualización.

Actualizando [dbo].[DatabaseLog]
[PK_DatabaseLog_DatabaseLogID] ha sido actualizado...
1 índice(s)/estadística(s) han sido actualizados, 0 no requirió actualización.

Actualizando [sys].[fulltext_avdl_1077578877]
[clust] ha sido actualizado...
1 índice(s)/estadística(s) han sido actualizados, 0 no requirió actualización.

Actualizando [Person].[Person]
[PK_Person_BusinessEntityID], la actualización no es necesaria...
[IX_Person_LastName_FirstName_MiddleName] ha sido actualizado...
[AK_Person_rowguid], la actualización no es necesaria...
1 Se actualizaron los índices/estadísticas, 2 no requirieron actualización.

Actualizando [Sales].[SalesReason]
[PK_SalesReason_SalesReasonID] ha sido actualizado...
1 índice(s)/estadística(s) han sido actualizados, 0 no requirió actualización.

Actualizando [Producción].[Producto]
[PK_Product_ProductID], la actualización no es necesaria...
[AK_Product_ProductNumber], la actualización no es necesaria...
[AK_Product_Name] ha sido actualizado...
[ AK_Product_rowguid], la actualización no es necesaria...
[_WA_Sys_00000013_75A278F5], la actualización no es necesaria...
[_WA_Sys_00000014_75A278F5], la actualización no es necesaria...
[_WA_Sys_0000000D_75A278F5], la actualización no es necesaria...
[_WA_Sys_0000000C_75A278F5], la actualización no es necesaria...
1 índice(s)/estadística(s) han sido actualizados, 7 no requirieron actualización.

Se han actualizado las estadísticas de todas las tablas.

La última línea de la salida es un poco engañosa:las estadísticas de todas las tablas no se han actualizado, solo se han actualizado las estadísticas que han tenido una o más filas modificadas. Y nuevamente, el inconveniente de eso es que tal vez se usaron recursos que no era necesario. Si una estadística solo tiene una fila modificada, ¿debería actualizarse? No. Si tiene 10.000 filas actualizadas, ¿debería actualizarse? Bueno eso depende. Si la tabla solo tiene 5000 filas, entonces absolutamente; si la tabla tiene 1 millón de filas, entonces no, ya que solo se ha modificado el uno por ciento de la tabla.

La conclusión aquí es que si está utilizando sp_updatestats para actualizar sus estadísticas, lo más probable es que esté desperdiciando recursos, incluidos CPU, E/S y tempdb. Además, se necesita tiempo para actualizar cada estadística, y si tiene una ventana de mantenimiento ajustada, probablemente tenga otras tareas de mantenimiento que se pueden ejecutar en ese tiempo, en lugar de actualizaciones innecesarias. Finalmente, probablemente no esté proporcionando ningún beneficio de rendimiento al actualizar las estadísticas cuando han cambiado tan pocas filas. Es probable que el cambio de distribución sea insignificante si solo se ha modificado un pequeño porcentaje de filas, por lo que los valores de histograma y densidad no terminan cambiando tanto. Además, recuerde que la actualización de estadísticas invalida los planes de consulta que usan esas estadísticas. Cuando se ejecutan esas consultas, los planes se vuelven a generar y el plan probablemente será exactamente el mismo que antes, porque no hubo cambios significativos en el histograma. La recompilación de planes de consulta tiene un costo:no siempre es fácil de medir, pero no debe ignorarse.

Un mejor método para administrar estadísticas, porque necesita administrar estadísticas, es implementar un trabajo programado que se actualice en función de los porcentajes de filas que se han modificado. Puede usar la consulta antes mencionada que interroga sys.sysindexes , o puede usar la consulta a continuación que aprovecha el nuevo DMF agregado en SQL Server 2008 R2 SP2 y SQL Server 2012 SP1:

SELECT [sch].[name] + '.' + [so].[name] AS [TableName] ,
[ss].[name] AS [Statistic],
[sp].[last_updated] AS [StatsLastUpdated] ,
[sp].[rows] AS [RowsInTable] ,
[sp].[rows_sampled] AS [RowsSampled] ,
[sp].[modification_counter] AS [RowModifications]
FROM [sys].[stats] [ss]
JOIN [sys].[objects] [so] ON [ss].[object_id] = [so].[object_id]
JOIN [sys].[schemas] [sch] ON [so].[schema_id] = [sch].[schema_id]
OUTER APPLY [sys].[dm_db_stats_properties]([so].[object_id],
[ss].[stats_id]) sp
WHERE [so].[type] = 'U'
AND [sp].[modification_counter] > 0
ORDER BY [sp].[last_updated] DESC;

Tenga en cuenta que diferentes tablas pueden tener diferentes umbrales y deberá modificar la consulta anterior para sus bases de datos. Para algunas tablas, esperar hasta que se haya modificado el 15 % o el 20 % de las filas puede estar bien. Pero para otros, es posible que deba actualizar al 10% o incluso al 5%, según los valores reales y su sesgo. No hay bala de plata. Por mucho que amemos los absolutos, rara vez existen en SQL Server y las estadísticas no son una excepción. Todavía desea dejar habilitadas las estadísticas de actualización automática:es una seguridad que se activará si se pierde algo, al igual que el crecimiento automático para los archivos de su base de datos. Pero su mejor opción es conocer sus datos e implementar una metodología que le permita actualizar las estadísticas en función del porcentaje de filas modificadas.