Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como atualizar estatísticas do SQL Server para tabelas grandes


Em meu artigo anterior, abordei brevemente as estatísticas do banco de dados, sua importância e por que as estatísticas devem ser atualizadas. Além disso, demonstrei um processo passo a passo para criar um plano de manutenção do SQL Server para atualizar as estatísticas. Neste artigo, serão explicados os seguintes problemas:1. Como atualizar estatísticas usando o comando T-SQL. 2. Como identificar as tabelas frequentemente atualizadas usando T-SQL e também como atualizar as estatísticas das tabelas com dados frequentemente inseridos/atualizados/excluídos.

Atualizando estatísticas usando T-SQL


Você pode atualizar as estatísticas usando o script T-SQL. Se você deseja atualizar as estatísticas usando o T-SQL ou o estúdio de gerenciamento do SQL Server, você precisa do banco de dados ALTER permissão no banco de dados. Veja o exemplo de código T-SQL para atualizar as estatísticas de uma tabela específica:
UPDATE STATISTICS <schema_name>.<table_name>.

Vamos considerar o exemplo de atualização das estatísticas do OrderLines tabela dos WideWorldImporters base de dados. O script a seguir fará isso.
UPDATE STATISTICS [Sales].[OrderLines]

Se você deseja atualizar as estatísticas de um índice específico, pode usar o seguinte script:
UPDATE STATISTICS <schema_name>.<table_name> <index_name>

Caso você queira atualizar as estatísticas do IX_Sales_OrderLines_Perf_20160301_02 índice das OrderLines tabela, você pode executar o seguinte script:
UPDATE STATISTICS [Sales].[OrderLines] [IX_Sales_OrderLines_Perf_20160301_02]

Você também pode atualizar as estatísticas de todo o banco de dados. Se você tiver um banco de dados muito pequeno com poucas tabelas e pouca quantidade de dados, poderá atualizar as estatísticas de todas as tabelas em um banco de dados. Veja o seguinte roteiro:
USE wideworldimporters 
go 
EXEC Sp_updatestats

Atualizando estatísticas para tabelas com dados frequentemente inseridos/atualizados/excluídos


Em bancos de dados grandes, o agendamento do trabalho de estatísticas se torna complicado, especialmente quando você tem apenas algumas horas para realizar a manutenção do índice, atualizar as estatísticas e realizar outras tarefas de manutenção. Por um grande banco de dados quero dizer um banco de dados que contém milhares de tabelas e cada tabela contém milhares de linhas. Por exemplo, temos um banco de dados chamado X. Ele tem centenas de tabelas e cada tabela tem milhões de linhas. E apenas algumas tabelas são atualizadas com frequência. Outras tabelas raramente são alteradas e têm muito poucas transações realizadas nelas. Como mencionei antes, para manter o desempenho do banco de dados em dia, as estatísticas da tabela devem estar atualizadas. Então criamos um plano de manutenção SQL para atualizar as estatísticas de todas as tabelas dentro do banco de dados X. Quando o SQL Server atualiza as estatísticas de uma tabela, ele utiliza uma quantidade significativa de recursos que pode levar a um problema de desempenho. Portanto, leva muito tempo para atualizar as estatísticas de centenas de tabelas grandes e, enquanto as estatísticas estão sendo atualizadas, o desempenho do banco de dados diminui significativamente. Em tais circunstâncias, é sempre aconselhável atualizar as estatísticas apenas para as tabelas que são atualizadas com frequência. Você pode acompanhar as alterações no volume de dados ou no número de linhas ao longo do tempo usando as seguintes visualizações de gerenciamento dinâmico:1. sys.partitions fornece informações sobre o número total de linhas em uma tabela. 2. sys.dm_db_partition_stats fornece informações sobre contagens de linhas e contagens de páginas, por partição. 3. sys.dm_db_index_physical_stats fornece informações sobre o número de linhas e páginas, além de informações sobre fragmentação de índice e muito mais. Os detalhes sobre o volume de dados são importantes, mas não completam o quadro da atividade do banco de dados. Por exemplo, uma tabela de preparo com quase o mesmo número de registros pode ser excluída da tabela ou inserida em uma tabela todos os dias. Devido a isso, um instantâneo do número de linhas sugeriria que a tabela é estática. Pode ser possível que os registros adicionados e excluídos tenham valores muito diferentes que alterem fortemente a distribuição de dados. Nesse caso, a atualização automática das estatísticas no SQL Server torna as estatísticas sem sentido. Portanto, rastrear o número de modificações em uma tabela é muito útil. Isso pode ser feito das seguintes maneiras:1. rowmodctr coluna em sys.sysindexes 2. modified_count coluna em sys.system_internals_partition_columns 3. modification_counter column in sys.dm_db_stats_properties Assim, como expliquei anteriormente, se você tem tempo limitado para manutenção do banco de dados, é sempre aconselhável atualizar as estatísticas apenas para as tabelas com maior frequência de alteração de dados (inserir/atualizar/excluir). Para fazer isso com eficiência, criei um script que atualiza as estatísticas das tabelas “ativas”. O script executa as seguintes tarefas:• Declara os parâmetros necessários • Cria uma tabela temporária chamada #tempstatistics para armazenar o nome da tabela, o nome do esquema e o nome do banco de dados • Cria outra tabela chamada #tempdatabase para armazenar o nome do banco de dados. Primeiro, execute o seguinte script para criar duas tabelas:
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

Em seguida, escreva um loop while para criar uma consulta SQL dinâmica que itere por todos os bancos de dados e insira uma lista de tabelas que tenham um contador de modificação maior que 200 no #tempstatistics tabela. Para obter informações sobre alterações de dados, uso sys.dm_db_stats_properties . Estude o seguinte exemplo de código:
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

Agora, crie o segundo loop dentro do primeiro loop. Ele irá gerar uma consulta SQL dinâmica que atualiza as estatísticas com varredura completa. Veja o exemplo de código abaixo:
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

Quando a execução do script for concluída, todas as tabelas temporárias serão descartadas.
SELECT * 
    FROM   #tempstatistics 
    DROP TABLE #tempdatabases 
    DROP TABLE #tempstatistics

Todo o script aparecerá da seguinte forma:
--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

Você também pode automatizar esse script criando um trabalho do SQL Server Agent que o executará em um horário agendado. Uma instrução passo a passo para automatizar este trabalho é fornecida abaixo.

Criando um trabalho SQL


Primeiro, vamos criar um SQL Job para automatizar o processo. Para fazer isso, abra o SSMS, conecte-se ao servidor desejado e expanda SQL Server Agent, clique com o botão direito do mouse em Jobs e selecione Novo trabalho . No Novo trabalho caixa de diálogo, digite o nome desejado em Nome campo. Agora, clique em Etapas opção de menu no painel esquerdo do Novo trabalho caixa de diálogo e clique em Novo nas Etapas janela. Na Etapa de Novo Trabalho caixa de diálogo, que é aberta, forneça o nome desejado em Nome da etapa campo. Em seguida, selecione Script Transact-SQL (T-SQL) no Tipo caixa suspensa. Em seguida, selecione DBATools no banco de dados caixa suspensa e escreva a seguinte consulta na caixa de texto do comando:
EXEC Statistics_maintenance

Para configurar o agendamento do trabalho, clique em Schedules opção de menu em Novo trabalho caixa de diálogo. A Nova Agenda de Trabalho caixa de diálogo é aberta. No Nome campo, forneça o nome do agendamento desejado. Em nosso exemplo, queremos que esse job seja executado todas as noites à 1h, portanto, no Occurs caixa suspensa na Frequência seção, selecione Diariamente . No Ocorre uma vez em campo na Frequência diária seção, digite 01:00:00. Clique em OK para fechar a Nova Agenda de Trabalho janela e clique em OK novamente no Novo emprego caixa de diálogo para fechá-la. Agora vamos testar este trabalho. Em SQL Server Agent, clique com o botão direito do mouse em Update_Statistics_Daily . Caso o trabalho tenha sido executado com sucesso, você verá a seguinte janela.

Resumo


Neste artigo, os seguintes problemas foram abordados:1. Como atualizar as estatísticas de tabelas usando o script T-SQL. 2. Como obter informações sobre alterações no volume de dados e frequência de alterações de dados. 3. Como criar o script que atualiza as estatísticas das tabelas ativas. 4. Como criar um trabalho do SQL Server Agent para executar o script no horário agendado.