통계의 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')
그러나 이것이 의미있는 통계 개체인지 확인하려면 다음을 수행해야합니다.
dbcc show_statistics('dbo.test_table',cix_test_table)
따라서이 통계는 업데이트되지 않았습니다. 통계가 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
자동 업데이트 통계를 맹목적으로 비활성화하는 대신 데이터 세트가 기울어 졌는지 검사하려고합니다. 데이터에 심각한 차이가있는 경우 필터링 된 통계를 생성 한 다음 통계 업데이트를 수동으로 관리하는 것이 올바른 조치인지 결정해야합니다.
비뚤어 짐을 분석하려면 검사하려는 특정 통계 / 인덱스 조합 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
하여 해당 값에 대한 더 나은 추정을위한 추가 단계를 제공해야합니다.
필터링 된 통계가 제자리에 있으면 통계를 수동으로 업데이트 할 가능성을 볼 수 있습니다.