Devo desativar as "estatísticas de atualização automática" em um cenário de data warehousing?

12

Eu tenho um armazém de dados de 200 GB no SQL Server.

Tenho experimentado tempos de execução muito lentos para algumas consultas; por exemplo, 12 horas para uma deleteconsulta simples com um inner join.

Depois de fazer algumas pesquisas com os planos de execução, atualizei as estatísticas das 2 tabelas envolvidas na consulta, usando a WITH FULLSCANopção

A consulta agora é executada em menos de um segundo, portanto, parece que as estatísticas não estavam atualizadas.

Estou pensando auto update statisticsem desativar o banco de dados e executar UPDATE STATISTICSmanualmente após o carregamento do armazém de dados. O data warehouse é carregado de forma incremental a partir de um sistema ERP de origem diariamente, à noite.

Estou correto ao assumir que, auto update statisticsem um cenário de data warehousing, não é realmente útil? Em vez disso, faz mais sentido atualizar as estatísticas manualmente após o carregamento dos dados?

saso
fonte
Esta é uma leitura muito boa sobre estatísticas: simple-talk.com/sql/performance/… também executamos um trabalho diário usando a solução ola.hallengren.com/… da Ola para atualizar estatísticas em 1 TB de banco de dados. Eu não desativaria a opção de atualização automática de estatísticas.
Joy Walker
1
Depende muito de quantos registros existem em suas tabelas e quanto você adiciona em um lote. Em uma tabela de 1b onde você adiciona 20m de linhas por noite, suas estatísticas são atualizadas a cada 10 dias, o que não é ótimo.
JNK
2
Apenas FYI - existe um sinalizador de rastreamento (2371) para alterar o limite para atualização de estatísticas de 20% fixo para uma taxa de porcentagem dinâmica. Veja mais aqui: blogs.msdn.com/b/saponsqlserver/archive/2011/09/07/…
DaniSQL 11/13
Links muito informativos, obrigado! @ JNK: Sim, é um grande banco de dados. A tabela de preparação tem mais de 300m de linhas e, dependendo do dia em que inserimos algo entre 1m e 10m por dia. Analisará mais de perto as estatísticas, conforme proposto pela resposta abaixo.
S12

Respostas:

11

Aqui está um whitepaper sobre quando ocorre a atualização automática de estatísticas . Aqui estão os pontos destacados em relação às atualizações automáticas das estatísticas:

  • O tamanho da tabela passou de 0 a> 0 linhas (teste 1).
  • O número de linhas na tabela quando as estatísticas foram coletadas era 500 ou menos e o colmodctr da coluna inicial do objeto de estatísticas mudou em mais de 500 desde então (teste 2).
  • A tabela tinha mais de 500 linhas quando as estatísticas foram coletadas e o colmodctr da coluna principal do objeto de estatísticas foi alterado em mais de 500 + 20% do número de linhas na tabela quando as estatísticas foram reunidas (teste 3) .

Portanto, o @JNK destacou em um comentário que, se você tiver 1 bilhão de linhas em uma tabela, precisará ter 20.000.5000 gravações na primeira coluna da estatística para acionar uma atualização.

Vamos dar a seguinte estrutura:

CREATE TABLE dbo.test_table (
    test_table_id INTEGER IDENTITY(1,1) NOT NULL, 
    test_table_value VARCHAR(50), 
    test_table_value2 BIGINT, 
    test_table_value3 NUMERIC(10,2)
);

CREATE CLUSTERED INDEX cix_test_table ON dbo.test_table (test_table_id, test_table_value);

Agora podemos verificar o que aconteceu nas estatísticas terrestres.

select * 
    from sys.stats
        where object_id = OBJECT_ID('dbo.test_table')

stat_container

No entanto, para ver se este é um objeto estatístico significativo, precisamos:

dbcc show_statistics('dbo.test_table',cix_test_table)

histograma

Portanto, esta estatística não foi atualizada. Isso SELECTocorre porque parece que a estatística não é atualizada até que ocorra uma e, mesmo assim, ela SELECTprecisa ficar fora do que o SQL Server possui dentro de seu histograma. Aqui está um script de teste que eu corri para testar isso:

    CREATE TABLE test_table (
        test_table_id INTEGER IDENTITY(1,1) NOT NULL, 
        test_table_value VARCHAR(50), 
        test_table_value2 BIGINT, 
        test_table_value3 NUMERIC(10,2)
    );

    CREATE CLUSTERED INDEX cix_test_table ON test_table (test_table_id, test_table_value);

    ALTER TABLE test_table ADD CONSTRAINT pk_test_table PRIMARY KEY  (test_table_id)

    SELECT * 
        FROM sys.stats
            WHERE object_id = OBJECT_ID('dbo.test_table')

    --DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table)
    DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

declare @test int = 0

WHILE @test < 1
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT 'one row|select < 1', * FROM test_table WHERE test_table_id < 1;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

SET @test = 1

WHILE @test < 500
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '100 rows(add 99)|select < 100',* FROM test_table WHERE test_table_id < 100;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--get the table up to 500 rows/changes
WHILE @test < 500
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END
SELECT '500 rows(add 400)|select < 100',* FROM test_table WHERE test_table_id < 100;
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
SELECT '500 rows(add 400)|select < 500',* FROM test_table WHERE test_table_id < 500;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--bump it to 501
SET @test = 500;
WHILE @test < 501
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END


SELECT '501 rows(add 1)|select < 501',* FROM test_table WHERE test_table_id < 501;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 600
SET @test = 501;
WHILE @test < 600
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '600 rows (add 100)|select < 600',* FROM test_table WHERE test_table_id < 600;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 700
SET @test = 600;
WHILE @test < 700
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '700 rows (add 100)|select < 700', * FROM test_table WHERE test_table_id < 700;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 1200
SET @test = 700;
WHILE @test < 1200
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '1200 rows (add 500)|select < 1200',* FROM test_table WHERE test_table_id < 1200;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--DROP TABLE test_table

Em vez de desativar cegamente as estatísticas de auto_update, tentaria examinar seu conjunto de dados para distorção. Se os seus dados exibe distorção significativa, então você precisa considerar a criação de estatísticas filtradas e , em seguida, decidir se o gerenciamento de atualizações de estatísticas manualmente é o curso correto de ação.

Para analisar a inclinação, é necessário executar DBCC SHOW_STATISTICS(<stat_object>, <index_name>);(no script acima sem o WITH STAT_HEADER) na combinação estatística / índice específica que você deseja examinar. Uma maneira rápida de ocular sua inclinação seria olhar o histograma (terceiro conjunto de resultados) e verificar a variação na sua EQ_ROWS. Se for razoavelmente consistente, sua inclinação será mínima. Para intensificar, você olha a RANGE_ROWScoluna e a variação lá, pois isso mede quantas linhas existem entre cada etapa. Por fim, você pode pegar o [All density]resultado do DENSITY_VECTOR(segundo conjunto de resultados) e multiplicá-lo pelo [Rows Sampled]valor no STAT_HEADER(primeiro conjunto de resultados) e ver qual seria a expectativa média para uma consulta nessa coluna. Você compara essa média com a suaEQ_ROWS e se houver muitos lugares onde isso varia significativamente, você terá uma inclinação.

Se você achar que tem inclinação, precisará considerar a criação de algumas estatísticas filtradas nos intervalos que possuem alta muito alta, RANGE_ROWSpara que você possa dar etapas adicionais para obter melhores estimativas desses valores.

Depois de ter essas estatísticas filtradas em vigor, você poderá examinar a possibilidade de atualizar as estatísticas manualmente.

swasheck
fonte
Obrigado pela resposta abrangente. Não tenho muita experiência com estatísticas e isso parece ser mais complicado do que eu pensava. Definitivamente, olharemos mais de perto e seguiremos suas diretrizes.
saso 12/12