我应该在数据仓库中禁用“自动更新统计信息”吗?


12

我在SQL Server中有200 GB的数据仓库。

对于某些查询,我的执行时间一直很慢;例如12个小时的简单delete查询inner join

在对执行计划进行了一些研究之后,我使用该WITH FULLSCAN选项更新了查询中涉及的2个表的统计信息。

现在查询将在不到一秒钟的时间内执行,因此看来统计信息不是最新的。

我正在考虑禁用auto update statistics数据库,并UPDATE STATISTICS在加载数据仓库后手动运行。每天晚上,从源ERP系统增量加载数据仓库。

我假设auto update statistics在数据仓库场景中不是真的有用吗?相反,加载数据后手动更新统计信息是否更有意义?


这是有关统计的非常好阅读:simple-talk.com/sql/performance/…我们还使用Ola的解决方案ola.hallengren.com/… 来运行日常工作,以更新有关1TB db的统计信息。我不会禁用自动更新统计信息选项。
Joy Walker 2013年

1
这在很大程度上取决于表中有多少条记录以及批处理中添加了多少条记录。在一个1b行表中,您每晚增加2000万行,统计信息大约每10天更新一次,效果不佳。
JNK 2013年

2
仅供参考-有跟踪标记(2371)可以将统计信息更新的阈值从固定的20%更改为动态百分比。查看更多在这里:blogs.msdn.com/b/saponsqlserver/archive/2011/09/07/...
DaniSQL

非常有用的链接,谢谢!@JNK:是的,它是一个大型数据库。临时表有300m +行,根据每天插入的数据,我们每天插入1m至10m之间的内容。正如下面的答案所建议的那样,将更仔细地查看统计数据。
saso 2013年

Answers:


11

这是关于何时自动更新统计信息的白皮书。以下是自动更新统计信息的要点:

  • 表的大小从0行增加到0行以上(测试1)。
  • 收集统计信息时表中的行数为500或更少,并且此后统计信息对象的前列的colmodctr更改了500多个(测试2)。
  • 收集统计信息时,该表具有超过500行,并且收集统计信息时,统计对象的前导列的colmodctr更改了表中的行数的500 + 20%以上(测试3) 。

因此,@ JNK在注释中指出,如果表中有10亿行,则需要对统计信息的第一列进行20,000,5000次写操作才能触发更新。

让我们采用以下结构:

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);

现在我们可以检查一下统计领域发生了什么。

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

stat_container

但是,要查看这是否是有意义的统计对象,我们需要:

dbcc show_statistics('dbo.test_table',cix_test_table)

直方图

因此,该统计信息尚未更新。那是因为看起来统计数据直到a SELECT出现才更新,即使如此,它SELECT也必须超出SQL Server在其直方图中的范围。这是我用来测试的测试脚本:

    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

与其盲目地禁用auto_update统计信息,不如尝试检查您的数据集是否倾斜。如果数据表现出明显的偏差,那么您需要考虑创建过滤的统计信息,然后决定手动管理统计信息更新是否是正确的做法。

要分析偏斜,您需要DBCC SHOW_STATISTICS(<stat_object>, <index_name>);WITH STAT_HEADER要检查的特定统计信息/索引组合上运行(在上面的脚本中,没有)。观察偏斜的一种快速方法是查看直方图(第三结果集),并检查中的方差EQ_ROWS。如果相当一致,则您的歪斜很小。要逐步提高它,您需要查看该RANGE_ROWS列并查看其中的差异,因为这可以衡量每个步骤之间存在多少行。最后,您可以[All density]DENSITY_VECTOR(第二个结果集)中获取结果,并将其乘以(第一个结果集)中的[Rows Sampled]值,STAT_HEADER然后查看对该列查询的平均期望值。您将该平均值与您的平均值进行比较EQ_ROWS 如果在很多地方变化很大,那您就会有偏差。

如果发现确实存在偏斜,则需要考虑在具有很高或很高的范围上创建一些过滤的统计信息,RANGE_ROWS以便您可以给出其他步骤以更好地估计这些值。

一旦有了这些过滤的统计信息,便可以查看手动更新统计信息的可能性。


感谢您的全面答复。我没有太多的统计经验,这似乎更加棘手。一定会仔细研究并遵循您的指南。
saso
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.