Odpowiedzi:
Podczas aktualizowania statystyk możesz wziąć pod uwagę następujące kwestie (skopiowane z Przebudowy Indeksów vs. Aktualizacji Statystyki (Benjamin Nevarez)
Domyślnie UPDATE STATISTICS
instrukcja używa tylko próbki rekordów tabeli. Używanie UPDATE STATISTICS WITH FULLSCAN
spowoduje przeskanowanie całej tabeli.
Domyślnie UPDATE STATISTICS
instrukcja aktualizuje statystyki indeksu i kolumny. Użycie tej COLUMNS
opcji spowoduje aktualizację tylko statystyk kolumn. Użycie tej INDEX
opcji spowoduje aktualizację tylko statystyk indeksu.
Odbudowanie indeksu , na przykład za pomocą, ALTER INDEX … REBUILD
spowoduje również zaktualizowanie statystyki indeksu za pomocą równoważnika użycia, WITH FULLSCAN
chyba że tabela zostanie podzielona na partycje, w którym to przypadku statystyki są tylko próbkowane (dotyczy SQL Server 2012 i nowszych).
Statystyki utworzone ręcznie przy użyciu CREATE STATISTICS
nie są aktualizowane przez żadną ALTER INDEX ... REBUILD
operację, w tym ALTER TABLE ... REBUILD
. ALTER TABLE ... REBUILD
aktualizuje statystyki dla indeksu klastrowanego, jeśli jest on zdefiniowany w odbudowywanej tabeli.
Reorganizacja indeksu , na przykład za pomocą ALTER INDEX … REORGANIZE
, nie aktualizuje żadnych statystyk.
Krótka odpowiedź brzmi: musisz użyć, UPDATE STATISTICS
aby zaktualizować statystyki kolumn i że przebudowa indeksu zaktualizuje tylko statystyki indeksu. Możesz wymusić aktualizację wszystkich statystyk w tabeli, w tym statystyk indeksów i statystyk utworzonych ręcznie, przy użyciu UPDATE STATISTICS (tablename) WITH FULLSCAN;
składni.
Poniższy kod ilustruje powyższe reguły:
Najpierw utworzymy tabelę z kilkoma kolumnami i indeksem klastrowym:
USE tempdb;
IF OBJECT_ID(N'dbo.SomeTable', N'U') IS NOT NULL
DROP TABLE dbo.SomeTable;
CREATE TABLE dbo.SomeTable
(
rn int NOT NULL IDENTITY(1,1)
CONSTRAINT pk
PRIMARY KEY NONCLUSTERED
, i int NOT NULL INDEX i
, d sysname NOT NULL
) ON [PRIMARY] WITH (DATA_COMPRESSION = NONE);
CREATE UNIQUE CLUSTERED INDEX cx ON dbo.SomeTable (i, d);
CREATE STATISTICS d ON dbo.SomeTable (d) WITH FULLSCAN;
INSERT INTO dbo.SomeTable (d, i)
SELECT c1.name, c1.id
FROM sys.syscolumns c1;
To zapytanie pokazuje datę ostatniej aktualizacji każdego obiektu statystyki:
SELECT ObjectName = sc.name + N'.' + o.name
, StatsName = s.name
, StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
AND o.name = N'SomeTable';
Wyniki pokazują, że nie nastąpiły jeszcze żadne aktualizacje, co jest poprawne, ponieważ właśnie utworzyliśmy tabelę:
╔═══════════════╦═══════════╦═══════════╗ ║ ObjectName ║ StatsName ║ StatsDate ║ ╠═══════════════╬═══════════╬═══════════╣ ║ dbo.SomeTable ║ cx ║ NULL ║ ║ dbo.SomeTable ║ i ║ NULL ║ ║ dbo.SomeTable ║ pk ║ NULL ║ ║ dbo.SomeTable ║ d ║ NULL ║ ╚═══════════════╩═══════════╩═══════════╝
Przebudujmy całą tabelę i zobaczmy, czy to aktualizuje statystyki:
ALTER TABLE dbo.SomeTable REBUILD;
SELECT ObjectName = sc.name + N'.' + o.name
, StatsName = s.name
, StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
AND o.name = N'SomeTable';
╔═══════════════╦═══════════╦═════════════════════ ════╗ ║ ObjectName ║ StatsName ║ StatsDate ║ ╠═══════════════╬═══════════╬═════════════════════ ════╣ ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║ ║ dbo.SomeTable ║ i ║ NULL ║ ║ dbo.SomeTable ║ pk ║ NULL ║ ║ dbo.SomeTable ║ d ║ NULL ║ ╚═══════════════╩═══════════╩═════════════════════ ════╝
Wyniki pokazują, że tylko statystyki indeksu klastrowego zostały zaktualizowane.
Następnie wykonujemy dyskretną UPDATE STATS
operację:
UPDATE STATISTICS dbo.SomeTable(d) WITH FULLSCAN;
SELECT ObjectName = sc.name + N'.' + o.name
, StatsName = s.name
, StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
AND o.name = N'SomeTable';
Jak widać, właśnie zaktualizowaliśmy statystyki w d
kolumnie:
╔═══════════════╦═══════════╦═════════════════════ ════╗ ║ ObjectName ║ StatsName ║ StatsDate ║ ╠═══════════════╬═══════════╬═════════════════════ ════╣ ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║ ║ dbo.SomeTable ║ i ║ NULL ║ ║ dbo.SomeTable ║ pk ║ NULL ║ ║ dbo.SomeTable ║ d ║ 2018-09-17 14: 09: 13.597 ║ ╚═══════════════╩═══════════╩═════════════════════ ════╝
Teraz zaktualizujemy statystyki dla całej tabeli:
UPDATE STATISTICS dbo.SomeTable WITH FULLSCAN;
SELECT ObjectName = sc.name + N'.' + o.name
, StatsName = s.name
, StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
AND o.name = N'SomeTable';
╔═══════════════╦═══════════╦═════════════════════ ════╗ ║ ObjectName ║ StatsName ║ StatsDate ║ ╠═══════════════╬═══════════╬═════════════════════ ════╣ ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.600 ║ ║ dbo.SomeTable ║ i ║ 2018-09-17 14: 09: 13.600 ║ ║ dbo.SomeTable ║ pk ║ 2018-09-17 14: 09: 13.603 ║ ║ dbo.SomeTable ║ d ║ 2018-09-17 14: 09: 13.607 ║ ╚═══════════════╩═══════════╩═════════════════════ ════╝
Jak widać, jedynym sposobem na upewnienie się, że wszystkie statystyki są aktualizowane, jest albo aktualizacja każdej z nich ręcznie, albo aktualizacja całej tabeli UPDATE STATISTICS (table);
.
ALTER INDEX ... REBUILD
lub UPDATE STATISTICS
instrukcji. Jeśli sama tabela zostanie przebudowana, aktualizowane są tylko statystyki indeksu klastrowego. FYI, klucz podstawowy i indeks klastrowany niekoniecznie są obsługiwane przez ten sam obiekt indeksu.
Na stronie Microsoft SQL Server Docs dla statystyki stanów :
Operacje takie jak odbudowywanie, defragmentacja lub reorganizacja indeksu nie zmieniają dystrybucji danych. Dlatego nie trzeba aktualizować statystyk po wykonaniu operacji ALTER INDEX REBUILD, DBCC DBREINDEX, DBCC INDEXDEFRAG lub ALTER INDEX REORGANIZE . Optymalizator zapytań aktualizuje statystyki podczas odbudowywania indeksu w tabeli lub widoku za pomocą ALTER INDEX REBUILD lub DBCC DBREINDEX, jednak ta aktualizacja statystyk jest produktem ubocznym ponownego tworzenia indeksu. Optymalizator zapytań nie aktualizuje statystyk po operacjach DBCC INDEXDEFRAG lub ALTER INDEX REORGANIZE.
REINDEX
nie aktualizuje statystyk kolumn jako efekt uboczny przebudowy indeksu - nie trzeba aktualizować statystyk. Dane w tabeli się nie zmieniają. To te same dane, tylko: a) przeniósł swoją lokalizację na obracający się talerz (gdy strona jest reorganizowana) lub b) siedzi na innej stronie (w przypadku przebudowy). Więc: re-index robi aktualizacji (troche) statystyki: nie ma potrzeby, aby to zrobić.