데이터웨어 하우징 시나리오에서 "자동 업데이트 통계"를 비활성화해야합니까?


12

SQL Server에 200GB 데이터웨어 하우스가 있습니다.

일부 쿼리의 실행 시간이 실제로 느려졌습니다. 예를 들어 12 시간의 간단한 delete쿼리의 경우 12 시간입니다 inner join.

실행 계획을 조사한 후 WITH FULLSCAN옵션을 사용하여 쿼리와 관련된 두 테이블의 통계를 업데이트했습니다 .

이제 쿼리가 1 초 이내에 실행되므로 통계가 최신 상태가 아닌 것으로 보입니다.

auto update statistics데이터베이스에서 비활성화 UPDATE STATISTICS하고 데이터웨어 하우스가로드 된 후 수동으로 실행하는 것을 고려 하고 있습니다 . 데이터웨어 하우스는 매일 밤 매일 소스 ERP 시스템에서 점진적으로로드됩니다.

auto update statistics데이터웨어 하우징 시나리오에서 실제로 유용하지 않다고 가정하면 정확 합니까? 대신, 데이터가로드 된 후 통계를 수동으로 업데이트하는 것이 더 합리적입니까?


이것은 통계에 대해 매우 잘 읽습니다. simple-talk.com/sql/performance/… 또한 1TB db의 통계를 업데이트하기 위해 Ola의 솔루션 ola.hallengren.com/… 을 사용하여 매일 작업을 실행합니다 . 자동 업데이트 통계 옵션을 비활성화하지 않습니다.
Joy Walker

1
그것은 테이블에 얼마나 많은 레코드가 있고 배치에 얼마나 많이 추가하는지에 달려 있습니다. 밤에 20m 행을 추가하는 1b 행 테이블에서 통계는 약 10 일마다 업데이트되므로 좋지 않습니다.
JNK

2
참고로 통계 업데이트 임계 값을 고정 20 %에서 동적 백분율로 변경하는 추적 플래그 (2371)가 있습니다. 자세한 내용은 여기를 참조하십시오 : blogs.msdn.com/b/saponsqlserver/archive/2011/09/07/…
DaniSQL

매우 유익한 링크, 감사합니다! @ JNK : 예, 그것은 큰 DB입니다. 준비 테이블에는 300m + 행이 있으며 매일 1m에서 10m 사이에 무언가를 삽입하는 날에 따라 다릅니다. 아래 답변에서 제안한대로 통계를 더 자세히 살펴볼 것입니다.
saso

답변:


11

통계의 auto_update가 발생할 때의 백서입니다 . 통계에 대한 자동 업데이트에 대한 주요 사항은 다음과 같습니다.

  • 테이블 크기가 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)

히스토그램

따라서이 통계는 업데이트되지 않았습니다. 통계가 SELECT발생하기 전까지 업데이트되지 않은 것처럼 보이고 SELECTSQL 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

자동 업데이트 통계를 맹목적으로 비활성화하는 대신 데이터 세트가 기울어 졌는지 검사하려고합니다. 데이터에 심각한 차이가있는 경우 필터링 된 통계를 생성 한 다음 통계 업데이트를 수동으로 관리하는 것이 올바른 조치인지 결정해야합니다.

비뚤어 짐을 분석하려면 검사하려는 특정 통계 / 인덱스 조합 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.