sql >> Base de Datos >  >> RDS >> Sqlserver

Cómo actualizar las estadísticas de SQL Server para tablas grandes

En mi artículo anterior, cubrí brevemente las estadísticas de la base de datos, su importancia y por qué se deben actualizar las estadísticas. Además, he demostrado un proceso paso a paso para crear un plan de mantenimiento de SQL Server para actualizar las estadísticas. En este artículo, se explicarán los siguientes temas:1. Cómo actualizar estadísticas usando el comando T-SQL. 2. Cómo identificar las tablas que se actualizan con frecuencia utilizando T-SQL y también cómo actualizar las estadísticas de las tablas con datos insertados/actualizados/eliminados con frecuencia.

Actualización de estadísticas usando T-SQL

Puede actualizar las estadísticas utilizando el script T-SQL. Si desea actualizar las estadísticas utilizando T-SQL o SQL Server Management Studio, necesita una base de datos ALTER. permiso en la base de datos. Vea el ejemplo de código T-SQL para actualizar las estadísticas de una tabla específica:

UPDATE STATISTICS <schema_name>.<table_name>.

Consideremos el ejemplo de actualizar las estadísticas de las Líneas de Pedido tabla de los WideWorldImporters base de datos. El siguiente script hará eso.

UPDATE STATISTICS [Sales].[OrderLines]

Si desea actualizar las estadísticas de un índice específico, puede utilizar el siguiente script:

UPDATE STATISTICS <schema_name>.<table_name> <index_name>

En caso de querer actualizar las estadísticas del IX_Sales_OrderLines_Perf_20160301_02 índice de las Líneas de pedido tabla, puede ejecutar el siguiente script:

UPDATE STATISTICS [Sales].[OrderLines] [IX_Sales_OrderLines_Perf_20160301_02]

También puede actualizar las estadísticas de toda la base de datos. Si tiene una base de datos muy pequeña con pocas tablas y poca cantidad de datos, puede actualizar las estadísticas de todas las tablas dentro de una base de datos. Consulte el siguiente guión:

USE wideworldimporters 
go 
EXEC Sp_updatestats

Actualización de estadísticas para tablas con datos frecuentemente insertados/actualizados/eliminados

En bases de datos grandes, la programación del trabajo de estadísticas se vuelve complicada, especialmente cuando solo tiene unas pocas horas para realizar el mantenimiento del índice, actualizar las estadísticas y realizar otras tareas de mantenimiento. Por una base de datos grande me refiero a una base de datos que contiene miles de tablas y cada tabla contiene miles de filas. Por ejemplo, tenemos una base de datos llamada X. Tiene cientos de tablas y cada tabla tiene millones de filas. Y solo unas pocas tablas se actualizan con frecuencia. Otras tablas rara vez se modifican y se realizan muy pocas transacciones en ellas. Como mencioné antes, para mantener el rendimiento de la base de datos a la altura, las estadísticas de la tabla deben estar actualizadas. Entonces creamos un plan de mantenimiento de SQL para actualizar las estadísticas de todas las tablas dentro de la base de datos X. Cuando el servidor SQL actualiza las estadísticas de una tabla, utiliza una cantidad significativa de recursos que pueden generar un problema de rendimiento. Por lo tanto, lleva mucho tiempo actualizar las estadísticas de cientos de tablas grandes y, mientras se actualizan las estadísticas, el rendimiento de la base de datos se reduce significativamente. En tales circunstancias, siempre es recomendable actualizar las estadísticas solo para las tablas que se actualizan con frecuencia. Puede realizar un seguimiento de los cambios en el volumen de datos o la cantidad de filas a lo largo del tiempo mediante las siguientes vistas de administración dinámica:1. sys.partitions proporciona información sobre el número total de filas en una tabla. 2. sys.dm_db_partition_stats proporciona información sobre recuentos de filas y recuentos de páginas, por partición. 3. sys.dm_db_index_physical_stats proporciona información sobre el número de filas y páginas, además de información sobre la fragmentación del índice y más. Los detalles sobre el volumen de datos son importantes, pero no completan la imagen de la actividad de la base de datos. Por ejemplo, una tabla de etapas que tiene casi la misma cantidad de registros se puede eliminar de la tabla o insertar en una tabla todos los días. Debido a eso, una instantánea del número de filas sugeriría que la tabla es estática. Es posible que los registros agregados y eliminados tengan valores muy diferentes que cambien mucho la distribución de datos. En este caso, la actualización automática de estadísticas en SQL Server hace que las estadísticas no tengan sentido. Por lo tanto, el seguimiento del número de modificaciones de una tabla es muy útil. Esto se puede hacer de las siguientes maneras:1. rowmodctr columna en sys.sysindexes 2. modified_count columna en sys.system_internals_partition_columns 3. modification_counter columna en sys.dm_db_stats_properties Por lo tanto, como expliqué anteriormente, si tiene un tiempo limitado para el mantenimiento de la base de datos, siempre es recomendable actualizar las estadísticas solo para las tablas con una mayor frecuencia de cambio de datos (insertar / actualizar / eliminar). Para hacerlo de manera eficiente, he creado un script que actualiza las estadísticas de las tablas "activas". El script realiza las siguientes tareas:• Declara los parámetros requeridos • Crea una tabla temporal llamada #tempstatistics para almacenar el nombre de la tabla, el nombre del esquema y el nombre de la base de datos • Crea otra tabla llamada #tempdatabase para almacenar el nombre de la base de datos. Primero, ejecute el siguiente script para crear dos tablas:

DECLARE @databasename VARCHAR(500) 
DECLARE @i INT=0 
DECLARE @DBCOunt INT 
DECLARE @SQLCOmmand NVARCHAR(max) 
DECLARE @StatsUpdateCOmmand NVARCHAR(max) 

CREATE TABLE #tempstatistics 
  ( 
     databasename VARCHAR(max), 
     tablename    VARCHAR(max), 
     schemaname   VARCHAR(max) 
  ) 

CREATE TABLE #tempdatabases 
  ( 
     databasename VARCHAR(max) 
  ) 

INSERT INTO #tempdatabases 
            (databasename) 
SELECT NAME 
FROM   sys.databases 
WHERE  database_id > 4 
ORDER  BY NAME

A continuación, escriba un bucle while para crear una consulta SQL dinámica que recorra todas las bases de datos e inserte una lista de tablas que tienen un contador de modificaciones superior a 200 en #tempstatistics. mesa. Para obtener información sobre cambios de datos, uso sys.dm_db_stats_properties . Estudie el siguiente código de ejemplo:

SET @DBCOunt=(SELECT Count(*) 
                    FROM   #tempdatabases) 
      WHILE ( @i < @DBCOunt ) 
        BEGIN 
            DECLARE @DBName VARCHAR(max) 
            SET @DBName=(SELECT TOP 1 databasename 
                         FROM   #tempdatabases) 
            SET @SQLCOmmand= '     use [' + @DBName + '];     select 
distinct ''' + @DBName+ ''', a.TableName,a.SchemaName from (SELECT obj.name as TableName, b.name as SchemaName,obj.object_id, stat.name, stat.stats_id, last_updated, modification_counter       FROM [' + @DBName+ '].sys.objects AS obj     inner join ['+ @DBName + '].sys.schemas b on obj.schema_id=b.schema_id   INNER JOIN [' + @DBName+ '].sys.stats AS stat ON stat.object_id = obj.object_id    CROSS APPLY [' + @DBName+'].sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp WHERE modification_counter > 200 and obj.name not like ''sys%''and b.name not like 
''sys%'')a' 
    INSERT INTO #tempstatistics 
                (databasename, 
                 tablename, 
                 schemaname) 
    EXEC Sp_executesql 
      @SQLCOmmand

Ahora, crea el segundo bucle dentro del primer bucle. Generará una consulta SQL dinámica que actualiza las estadísticas con un análisis completo. Vea el ejemplo de código a continuación:

DECLARE @j INT=0 
    DECLARE @StatCount INT 

    SET @StatCount =(SELECT Count(*) 
                     FROM   #tempstatistics) 

    WHILE @J < @StatCount 
      BEGIN 
          DECLARE @DatabaseName_Stats VARCHAR(max) 
          DECLARE @Table_Stats VARCHAR(max) 
          DECLARE @Schema_Stats VARCHAR(max) 
          DECLARE @StatUpdateCommand NVARCHAR(max) 

          SET @DatabaseName_Stats=(SELECT TOP 1 databasename 
                                   FROM   #tempstatistics) 
          SET @Table_Stats=(SELECT TOP 1 tablename 
                            FROM   #tempstatistics) 
          SET @Schema_Stats=(SELECT TOP 1 schemaname 
                             FROM   #tempstatistics) 
          SET @StatUpdateCommand='Update Statistics [' + @DatabaseName_Stats 
                                 + '].[' + @Schema_Stats + '].[' + @Table_Stats 
                                 + '] with fullscan' 
          EXEC Sp_executesql 
            @StatUpdateCommand 
          SET @[email protected] + 1 
          DELETE FROM #tempstatistics 
          WHERE  databasename = @DatabaseName_Stats 
                 AND tablename = @Table_Stats 
                 AND schemaname = @Schema_Stats 
      END 
    SET @[email protected] + 1 
    DELETE FROM #tempdatabases 
    WHERE  databasename = @DBName 
END

Una vez completada la ejecución del script, eliminará todas las tablas temporales.

SELECT * 
    FROM   #tempstatistics 
    DROP TABLE #tempdatabases 
    DROP TABLE #tempstatistics

El script completo aparecerá de la siguiente manera:

--set count on     
CREATE PROCEDURE Statistics_maintenance 
AS 
  BEGIN 
      DECLARE @databasename VARCHAR(500) 
      DECLARE @i INT=0 
      DECLARE @DBCOunt INT 
      DECLARE @SQLCOmmand NVARCHAR(max) 
      DECLARE @StatsUpdateCOmmand NVARCHAR(max) 
      CREATE TABLE #tempstatistics 
        ( 
           databasename VARCHAR(max), 
           tablename    VARCHAR(max), 
           schemaname   VARCHAR(max) 
        ) 
      CREATE TABLE #tempdatabases 
        ( 
           databasename VARCHAR(max) 
        ) 
      INSERT INTO #tempdatabases 
                  (databasename) 
      SELECT NAME 
      FROM   sys.databases 
      WHERE  database_id > 4  
      ORDER  BY NAME 
      SET @DBCOunt=(SELECT Count(*) 
                    FROM   #tempdatabases) 
      WHILE ( @i < @DBCOunt ) 
        BEGIN 
            DECLARE @DBName VARCHAR(max) 
            SET @DBName=(SELECT TOP 1 databasename 
                         FROM   #tempdatabases) 
            SET @SQLCOmmand= '     use [' + @DBName + '];     select 
distinct ''' + @DBName+ ''', a.TableName,a.SchemaName from (SELECT obj.name as TableName, b.name as SchemaName,obj.object_id, stat.name, stat.stats_id, last_updated, modification_counter       FROM [' + @DBName+ '].sys.objects AS obj     inner join ['+ @DBName + '].sys.schemas b on obj.schema_id=b.schema_id   INNER JOIN [' + @DBName+ '].sys.stats AS stat ON stat.object_id = obj.object_id    CROSS APPLY [' + @DBName+'].sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp WHERE modification_counter > 200 and obj.name not like ''sys%''and b.name not like 
''sys%'')a' 
    INSERT INTO #tempstatistics 
                (databasename, 
                 tablename, 
                 schemaname) 
    EXEC Sp_executesql 
      @SQLCOmmand 

    DECLARE @j INT=0 
    DECLARE @StatCount INT 

    SET @StatCount =(SELECT Count(*) 
                     FROM   #tempstatistics) 

    WHILE @J < @StatCount 
      BEGIN 
          DECLARE @DatabaseName_Stats VARCHAR(max) 
          DECLARE @Table_Stats VARCHAR(max) 
          DECLARE @Schema_Stats VARCHAR(max) 
          DECLARE @StatUpdateCommand NVARCHAR(max) 

          SET @DatabaseName_Stats=(SELECT TOP 1 databasename 
                                   FROM   #tempstatistics) 
          SET @Table_Stats=(SELECT TOP 1 tablename 
                            FROM   #tempstatistics) 
          SET @Schema_Stats=(SELECT TOP 1 schemaname 
                             FROM   #tempstatistics) 
          SET @StatUpdateCommand='Update Statistics [' + @DatabaseName_Stats 
                                 + '].[' + @Schema_Stats + '].[' + @Table_Stats 
                                 + '] with fullscan' 
          EXEC Sp_executesql 
            @StatUpdateCommand 
          SET @[email protected] + 1 
          DELETE FROM #tempstatistics 
          WHERE  databasename = @DatabaseName_Stats 
                 AND tablename = @Table_Stats 
                 AND schemaname = @Schema_Stats 
      END 
    SET @[email protected] + 1 
    DELETE FROM #tempdatabases 
    WHERE  databasename = @DBName 
END 
    SELECT * 
    FROM   #tempstatistics 
    DROP TABLE #tempdatabases 
    DROP TABLE #tempstatistics 
END

También puede automatizar este script creando un trabajo del Agente SQL Server que lo ejecutará a una hora programada. A continuación se proporciona una instrucción paso a paso para automatizar este trabajo.

Crear un trabajo SQL

Primero, creemos un trabajo SQL para automatizar el proceso. Para hacer eso, abra SSMS, conéctese al servidor deseado y expanda el Agente SQL Server, haga clic derecho en Trabajos y seleccione Nuevo trabajo . En el Nuevo Trabajo cuadro de diálogo, escriba el nombre deseado en el Nombre campo. Ahora, haga clic en Pasos opción de menú en el panel izquierdo de Nuevo trabajo cuadro de diálogo, luego haga clic en Nuevo en los Pasos ventana. En el paso de nuevo trabajo cuadro de diálogo que se abre, proporcione el nombre deseado en el Nombre del paso campo. A continuación, seleccione secuencia de comandos Transact-SQL (T-SQL) en el Tipo caja desplegable. Luego, seleccione DBATools en la Base de datos cuadro desplegable y escriba la siguiente consulta en el cuadro de texto del comando:

EXEC Statistics_maintenance

Para configurar la programación del trabajo, haga clic en Horarios opción de menú en el Nuevo trabajo caja de diálogo. El Programa de trabajo nuevo se abre el cuadro de diálogo. En el Nombre campo, proporcione el nombre del programa deseado. En nuestro ejemplo, queremos que este trabajo se ejecute todas las noches a la 1 a. m., por lo tanto, en Ocurre cuadro desplegable en Frecuencia sección, seleccione Diario . En el Ocurre una vez en campo en Frecuencia diaria sección, introduzca 01:00:00. Haga clic en Aceptar para cerrar el Programa de trabajo nuevo ventana y luego haga clic en OK de nuevo en el Nuevo Trabajo cuadro de diálogo para cerrarlo. Ahora probemos este trabajo. En Agente SQL Server, haga clic con el botón derecho en Update_Statistics_Daily . En caso de que el trabajo se haya ejecutado correctamente, verá la siguiente ventana.

Resumen

En este artículo, se han cubierto los siguientes temas:1. Cómo actualizar las estadísticas de las tablas usando T-SQL Script. 2. Cómo obtener información sobre los cambios en el volumen de datos y la frecuencia de los cambios de datos. 3. Cómo crear el script que actualiza las estadísticas en las tablas activas. 4. Cómo crear un trabajo del Agente SQL Server para ejecutar el script a la hora programada.