Hier ist ein Whitepaper darüber, wann die automatische Aktualisierung der Statistiken erfolgt . Hier sind die wichtigsten Punkte im Hinblick auf automatische Aktualisierungen von Statistiken:
- Die Tabellengröße ist von 0 auf> 0 Zeilen gestiegen (Test 1).
- Die Anzahl der Zeilen in der Tabelle, in der die Statistiken erfasst wurden, betrug 500 oder weniger, und der colmodctr der führenden Spalte des Statistikobjekts hat sich seitdem um mehr als 500 geändert (Test 2).
- Die Tabelle hatte mehr als 500 Zeilen, als die Statistiken erfasst wurden, und der colmodctr der führenden Spalte des Statistikobjekts hat sich um mehr als 500 + 20% der Anzahl der Zeilen in der Tabelle geändert, als die Statistiken erfasst wurden (Test 3). .
@JNK hat in einem Kommentar darauf hingewiesen, dass bei einer Milliarde Zeilen in einer Tabelle 20.000.5000 Schreibvorgänge in die erste Spalte der Statistik erforderlich sind, um eine Aktualisierung auszulösen.
Nehmen wir die folgende Struktur:
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);
Jetzt können wir überprüfen, was im Statistikland passiert ist.
select *
from sys.stats
where object_id = OBJECT_ID('dbo.test_table')
Um jedoch festzustellen, ob dies ein aussagekräftiges statistisches Objekt ist, müssen wir:
dbcc show_statistics('dbo.test_table',cix_test_table)
Diese Statistik wurde also nicht aktualisiert. Das liegt daran, dass die Statistik anscheinend erst aktualisiert wird, wenn a SELECT
auftritt, und selbst dann SELECT
muss die Statistik außerhalb dessen liegen, was SQL Server in seinem Histogramm hat. Hier ist ein Testskript, das ich ausgeführt habe, um dies zu testen:
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
Anstatt die auto_update-Statistik blind zu deaktivieren, würde ich versuchen, Ihren Datensatz auf Versatz zu untersuchen. Wenn Ihre Daten einen erheblichen Versatz aufweisen, müssen Sie die Erstellung gefilterter Statistiken in Betracht ziehen und dann entscheiden, ob die manuelle Verwaltung von Statistikaktualisierungen die richtige Vorgehensweise ist.
Um auf Versatz zu analysieren, müssen Sie DBCC SHOW_STATISTICS(<stat_object>, <index_name>);
(im obigen Skript ohne den WITH STAT_HEADER
) die bestimmte Statistik- / Indexkombination ausführen , die Sie untersuchen möchten. Eine schnelle Möglichkeit, Ihren Versatz in Augenschein zu nehmen, besteht darin, das Histogramm (dritte Ergebnismenge) zu betrachten und die Varianz in Ihrem zu überprüfen EQ_ROWS
. Wenn es ziemlich konsistent ist, ist Ihr Versatz minimal. Um dies zu erhöhen, sehen Sie sich die RANGE_ROWS
Spalte und die Varianz dort an, da hiermit gemessen wird, wie viele Zeilen zwischen den einzelnen Schritten vorhanden sind. Schließlich können Sie das [All density]
Ergebnis aus der DENSITY_VECTOR
(zweiten Ergebnismenge) entnehmen und mit dem [Rows Sampled]
Wert in der STAT_HEADER
(ersten Ergebnismenge ) multiplizieren, um zu sehen, wie hoch die durchschnittliche Erwartung für eine Abfrage in dieser Spalte wäre. Sie vergleichen diesen Durchschnitt mit IhremEQ_ROWS
Wenn es viele Stellen gibt, an denen es erheblich variiert, liegt ein Versatz vor.
Wenn Sie feststellen, dass Sie einen Versatz haben, müssen Sie einige gefilterte Statistiken zu den Bereichen erstellen, die sehr hoch sind, RANGE_ROWS
damit Sie zusätzliche Schritte für bessere Schätzungen dieser Werte angeben können.
Sobald Sie diese gefilterten Statistiken eingerichtet haben, können Sie die Möglichkeit prüfen, Statistiken manuell zu aktualisieren.