Aquí hay un documento técnico sobre cuándo se produce la actualización automática de estadísticas . Estos son los puntos más destacados con respecto a las actualizaciones automáticas de estadísticas:
- El tamaño de la tabla ha pasado de 0 a> 0 filas (prueba 1).
- El número de filas en la tabla cuando se recopilaron las estadísticas era de 500 o menos, y el colmodctr de la columna principal del objeto de estadísticas ha cambiado en más de 500 desde entonces (prueba 2).
- La tabla tenía más de 500 filas cuando se recopilaron las estadísticas, y el colmodctr de la columna inicial del objeto de estadísticas ha cambiado en más de 500 + 20% del número de filas en la tabla cuando se recopilaron las estadísticas (prueba 3) .
Entonces, @JNK señaló en un comentario que si tiene mil millones de filas en una tabla, necesitaría tener 20,000,5000 escrituras en la primera columna de la estadística para activar una actualización.
Tomemos la siguiente estructura:
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);
Ahora podemos verificar qué sucedió en las estadísticas de la tierra.
select *
from sys.stats
where object_id = OBJECT_ID('dbo.test_table')
Sin embargo, para ver si este es un objeto estadístico significativo, necesitamos:
dbcc show_statistics('dbo.test_table',cix_test_table)
Entonces esta estadística no se ha actualizado. Esto se debe a que parece que la estadística no se actualiza hasta que SELECT
ocurre un e incluso entonces SELECT
tiene que quedar fuera de lo que SQL Server tiene dentro de su histograma. Aquí hay un script de prueba que ejecuté para probar esto:
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
En lugar de deshabilitar ciegamente las estadísticas de auto_update, trataría de examinar su conjunto de datos en busca de sesgo. Si sus datos muestran un sesgo significativo, entonces debe considerar la creación de estadísticas filtradas y luego decidir si administrar las actualizaciones de estadísticas manualmente es el curso de acción correcto.
Para analizar la asimetría, debe ejecutar DBCC SHOW_STATISTICS(<stat_object>, <index_name>);
(en el script anterior sin el WITH STAT_HEADER
) la combinación estadística / índice particular que desea examinar. Una forma rápida de mirar su sesgo sería mirar el histograma (tercer conjunto de resultados) y verificar la varianza en su EQ_ROWS
. Si es bastante consistente, entonces tu sesgo es mínimo. Para avanzar, mire la RANGE_ROWS
columna y observe la varianza allí, ya que esto mide cuántas filas existen entre cada paso. Finalmente, puede tomar el [All density]
resultado del DENSITY_VECTOR
(segundo conjunto de resultados) y multiplicarlo por el [Rows Sampled]
valor en el STAT_HEADER
(primer conjunto de resultados) y ver cuál sería la expectativa promedio para una consulta en esa columna. Compara ese promedio con suEQ_ROWS
y si hay muchos lugares donde varía significativamente, entonces tienes sesgo.
Si encuentra que tiene sesgo, entonces debe considerar la creación de algunas estadísticas filtradas en los rangos que tienen alto muy alto RANGE_ROWS
para que pueda dar pasos adicionales para mejores estimaciones de esos valores.
Una vez que tenga estas estadísticas filtradas, puede ver la posibilidad de actualizar las estadísticas manualmente.