Ecco un white paper su quando si verifica l'auto_aggiornamento delle statistiche . Ecco i punti salienti rispetto agli aggiornamenti automatici delle statistiche:
- Le dimensioni della tabella sono passate da 0 a> 0 righe (test 1).
- Il numero di righe nella tabella al momento della raccolta delle statistiche era 500 o inferiore e da allora il colmodctr della colonna principale dell'oggetto statistico è cambiato di oltre 500 (test 2).
- La tabella aveva più di 500 righe al momento della raccolta delle statistiche e il colmodctr della colonna principale dell'oggetto statistico è cambiato di oltre il 500 + 20% del numero di righe nella tabella al momento della raccolta delle statistiche (test 3) .
Quindi @JNK ha sottolineato in un commento che se hai 1 miliardo di righe in una tabella, per attivare un aggiornamento dovresti avere 20.000.5000 scritture nella prima colonna della statistica.
Prendiamo la seguente struttura:
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);
Ora possiamo controllare per vedere cosa è successo nelle statistiche della terra.
select *
from sys.stats
where object_id = OBJECT_ID('dbo.test_table')
Tuttavia, per vedere se si tratta di un oggetto statistico significativo dobbiamo:
dbcc show_statistics('dbo.test_table',cix_test_table)
Quindi questa statistica non è stata aggiornata. Questo perché sembra che la statistica non venga aggiornata fino a quando non si SELECT
verifica e anche in questo caso SELECT
deve cadere al di fuori di ciò che SQL Server ha nel suo istogramma. Ecco uno script di test che ho eseguito per testare questo:
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
Invece di disabilitare ciecamente le statistiche di auto_update, proverei a esaminare il tuo set di dati per inclinarlo. Se i tuoi dati mostrano un'inclinazione significativa, devi considerare la creazione di statistiche filtrate e quindi decidere se la gestione manuale degli aggiornamenti delle statistiche è la linea di condotta corretta.
Per analizzare l'inclinazione è necessario eseguire DBCC SHOW_STATISTICS(<stat_object>, <index_name>);
(nello script sopra senza WITH STAT_HEADER
) la particolare combinazione stat / indice che si desidera esaminare. Un modo rapido per controllare il tuo disallineamento sarebbe guardare l'istogramma (terzo set di risultati) e verificare la varianza nel tuo EQ_ROWS
. Se è abbastanza coerente, l'inclinazione è minima. Per aumentarlo, guardi la RANGE_ROWS
colonna e guardi la varianza lì poiché questo misura quante righe esistono tra ogni passaggio. Infine, puoi prendere il [All density]
risultato dal DENSITY_VECTOR
(secondo set di risultati) e moltiplicarlo per il [Rows Sampled]
valore nel STAT_HEADER
(primo set di risultati) e vedere quale sarebbe l'attesa media per una query su quella colonna. Confronti quella media con la tuaEQ_ROWS
e se ci sono molti posti in cui varia in modo significativo, allora hai l'inclinazione.
Se scopri di avere un'inclinazione, devi considerare la creazione di alcune statistiche filtrate sugli intervalli che hanno valori molto alti in RANGE_ROWS
modo da poter fornire ulteriori passaggi per una migliore stima di tali valori.
Dopo aver installato queste statistiche filtrate, puoi esaminare la possibilità di aggiornare manualmente le statistiche.