Відповіді:
Ви можете пам’ятати про наступне, коли дбаєте про оновлення статистики (скопійовано з « Перебудова індексів проти оновлення статистики» (Бенджамін Неварес)
За замовчуванням в UPDATE STATISTICS
операторі використовується лише зразок записів таблиці. Використання UPDATE STATISTICS WITH FULLSCAN
сканує всю таблицю.
За замовчуванням UPDATE STATISTICS
оператор оновлює статистику індексу та стовпців. За допомогою цієї COLUMNS
опції буде оновлено лише статистику стовпців. Використання INDEX
опції оновить лише статистику індексу.
Перебудова індексу , наприклад, за допомогою використання ALTER INDEX … REBUILD
, також буде оновлювати статистику індексу з еквівалентом використання, WITH FULLSCAN
якщо таблиця не розділена, і в цьому випадку статистика вибирається лише (стосується SQL Server 2012 та пізніших версій).
Статистика, створена вручну за допомогою CREATE STATISTICS
, не оновлюється жодною ALTER INDEX ... REBUILD
операцією, в тому числі ALTER TABLE ... REBUILD
. ALTER TABLE ... REBUILD
робить оновлення статистики для кластерного індексу, якщо він визначений у таблиці, що перебудовується.
Реорганізація індексу , наприклад, використання ALTER INDEX … REORGANIZE
не оновлює будь-яку статистику.
Коротка відповідь полягає в тому, що вам потрібно використовувати UPDATE STATISTICS
для оновлення статистики стовпців і що відбудова індексу оновлюватиме лише статистику індексу. Ви можете примусити оновити всю статистику в таблиці, включаючи статистику індексу та статистику, створену вручну, за допомогою UPDATE STATISTICS (tablename) WITH FULLSCAN;
синтаксису.
Наступний код ілюструє правила, капсульовані вище:
Спочатку ми створимо таблицю з парою стовпців та кластерним індексом:
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;
Цей запит показує дату останнього оновлення кожного об'єкта статистики:
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';
Результати показують, що оновлення ще не відбулося, що правильно, оскільки ми щойно створили таблицю:
╔═══════════════╦═══════════╦═══════════╗ Ame Ім'я об’єкта ame Ім'я статистики ║ СтатДейт ║ ╠═══════════════╬═══════════╬═══════════╣ ║ dbo.SomeTable ║ cx ║ NULL ║ ║ dbo.SomeTable ║ i ║ NULL ║ ║ dbo.SomeTable ║ pk ║ NULL ║ ║ dbo.SomeTable ║ d ║ NULL ║ ╚═══════════════╩═══════════╩═══════════╝
Давайте відновимо всю таблицю і подивимось, чи це оновлення статистики:
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';
╔═══════════════╦═══════════╦═════════════════════ ════╗ Ame Ім'я об’єкта ame Ім'я статистики ║ СтатДейт ║ ╠═══════════════╬═══════════╬═════════════════════ ════╣ ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║ ║ dbo.SomeTable ║ i ║ NULL ║ ║ dbo.SomeTable ║ pk ║ NULL ║ ║ dbo.SomeTable ║ d ║ NULL ║ ╚═══════════════╩═══════════╩═════════════════════ ════╝
Результати показують, що оновлено лише кластерні статистичні показники .
Далі виконуємо дискретну UPDATE STATS
операцію:
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';
Як бачите, ми щойно оновлювали статистику d
стовпця:
╔═══════════════╦═══════════╦═════════════════════ ════╗ Ame Ім'я об’єкта ame Ім'я статистики ║ СтатДейт ║ ╠═══════════════╬═══════════╬═════════════════════ ════╣ ║ 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 ║ ╚═══════════════╩═══════════╩═════════════════════ ════╝
Тепер ми оновимо статистику для всієї таблиці:
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';
╔═══════════════╦═══════════╦═════════════════════ ════╗ Ame Ім'я об’єкта ame Ім'я статистики ║ СтатДейт ║ ╠═══════════════╬═══════════╬═════════════════════ ════╣ ║ 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 ║ ╚═══════════════╩═══════════╩═════════════════════ ════╝
Як бачите, єдиний спосіб бути впевненим, що всі статистичні дані оновлюються - це або оновлювати кожну вручну, або оновлювати всю таблицю UPDATE STATISTICS (table);
.
ALTER INDEX ... REBUILD
або через UPDATE STATISTICS
заяву. Якщо сама таблиця перебудована, оновлюється лише статистика кластерних індексів. FYI, первинний ключ та кластерний індекс не обов'язково підтримуються одним і тим же об'єктом індексу.
На сторінці "Документи Microsoft" для статистики SQL Server зазначено :
Такі операції, як перебудова, дефрагментація або реорганізація індексу, не змінюють розподіл даних. Тому вам не потрібно оновлювати статистику після виконання операцій ALTER INDEX REBUILD, DBCC DBREINDEX, DBCC INDEXDEFRAG або ALTER INDEX REORGANIZE . Оптимізатор запитів оновлює статистику під час перебудови індексу на таблиці або перегляду за допомогою ALTER INDEX REBUILD або DBCC DBREINDEX, однак це оновлення статистики є побічним продуктом відновлення індексу. Оптимізатор запитів не оновлює статистику після операцій DBCC INDEXDEFRAG або ALTER INDEX REORGANIZE.
REINDEX
оновлення статистики стовпців є побічним ефектом відновлення індексу - не потрібно оновлювати статистику. Дані в таблиці не змінюються. Це ті самі дані, він лише a) перемістив своє місце розташування на спінінг-платі (коли реорганізована сторінка) або b) сидячи на іншій сторінці (у разі повторної збірки). Отже: повторний індекс робить (деякі) оновлення статистики: немає необхідності робити це.