これは、統計の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)
したがって、この統計は更新されていません。これは、統計が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
調べたい特定のstat / indexの組み合わせで(上記のスクリプトではを使用せずに)実行する必要があります。スキューを目撃する簡単な方法は、ヒストグラム(3番目の結果セット)を見て、の分散を確認することEQ_ROWS
です。それがかなり一貫しているなら、あなたのスキューは最小限です。これをステップアップするには、RANGE_ROWS
列を見て分散を調べます。これは、各ステップの間に存在する行数を測定するためです。最後に、あなたが取ることができます[All density]
から、結果DENSITY_VECTOR
(2番目の結果セットを)と乗算することによって、その[Rows Sampled]
内の値STAT_HEADER
(最初の結果セット)と平均予想は次のようになり、その列上のクエリのためになるものを参照してください。あなたはその平均をあなたのと比較しますEQ_ROWS
大きく異なる場所が多数ある場合は、ゆがみがあります。
スキューがあることがわかった場合は、非常に高い範囲にフィルターを適用した統計を作成してRANGE_ROWS
、これらの値をより適切に推定できるように追加の手順を実行することを検討する必要があります。
これらのフィルタリングされた統計を配置したら、手動で統計を更新する可能性を確認できます。