Ось довідка про те, коли відбувається автоматичне оновлення статистики . Ось важливі моменти щодо автоматичних оновлень статистики:
- Розмір таблиці перемістився від 0 до> 0 рядків (тест 1).
- Кількість рядків у таблиці, коли збиралася статистика, становила 500 або менше, а комодктрик провідного стовпця об’єкта статистики з цього часу змінився більш ніж на 500 (тест 2).
- Коли зібрана статистика, таблиця мала більше 500 рядків, а комодктр провідного стовпця об’єкта статистики змінився більш ніж на 500 + 20% від кількості рядків у таблиці під час збирання статистики (тест 3) .
Тож @JNK зазначив у коментарі, що якщо у вас є 1 мільярд рядків у таблиці, вам потрібно буде мати 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
) відповідну комбінацію stat / index, яку ви хочете вивчити. Швидкий спосіб зав'язати очне яблуко - переглядати гістограму (третій набір результатів) і перевірити дисперсію вашої EQ_ROWS
. Якщо це досить послідовно, то ваш перекос мінімальний. Щоб активізувати це, ви дивитесь на RANGE_ROWS
стовпчик і дивитесь на дисперсію там, оскільки це вимірює кількість рядків між кожним кроком. Нарешті, ви можете взяти [All density]
результат із DENSITY_VECTOR
(другий набір результатів) і помножити його на [Rows Sampled]
значення в STAT_HEADER
(перший набір результатів) і побачити, яким буде середнє очікування для запиту в цьому стовпчику. Ви порівнюєте це середнє значення з вашимEQ_ROWS
і якщо є багато місць, де вона значно змінюється, то ви перекосилися.
Якщо ви виявите, що у вас є перекос, вам потрібно розглянути можливість створення декількох відфільтрованих статистичних даних про діапазони, які мають високий і дуже високий рівень, RANGE_ROWS
щоб ви могли дати додаткові кроки для кращих оцінок цих значень.
Коли у вас є відфільтрована статистика, ви зможете переглянути можливість вручну оновити статистику.