Вот технический документ, когда происходит автоматическое обновление статистики . Вот основные моменты в отношении автоматических обновлений статистики:
- Размер таблицы изменился с 0 до> 0 строк (тест 1).
- Число строк в таблице, когда собирались статистические данные, составляло 500 или менее, и с тех пор colmodctr ведущего столбца объекта статистики изменилось более чем на 500 (тест 2).
- На момент сбора статистики в таблице было более 500 строк, а colmodctr в первом столбце объекта статистики изменилось более чем на 500 + 20% от числа строк в таблице, когда была собрана статистика (тест 3) ,
Таким образом, @JNK указал в комментарии, что если у вас есть 1 миллиард строк в таблице, вам потребуется 20 000 5 000 записей в первый столбец статистики, чтобы запустить обновление.
Давайте возьмем следующую структуру:
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
Вместо того, чтобы слепо отключать статистику auto_update, я бы попытался проверить ваш набор данных на перекос. Если ваши данные демонстрируют значительный перекос, то вам нужно подумать о создании отфильтрованной статистики, а затем решить, является ли управление обновлениями статистики вручную правильным способом.
Чтобы проанализировать асимметрию, вам нужно запустить 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
чтобы вы могли дать дополнительные шаги для более точных оценок этих значений.
После того, как у вас есть эти отфильтрованные статистические данные, вы можете посмотреть на возможность ручного обновления статистики.