Ответы:
Когда вы заботитесь об обновлении статистики, вы можете помнить следующее (скопировано из « Перестроение индексов против обновления статистики» (Бенджамин Неварез)
По умолчанию 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';
Результаты показывают, что обновления еще не произошли, и это правильно, так как мы только что создали таблицу:
╔═══════════════╦═══════════╦═══════════╗ ║ ObjectName ║ StatsName ║ StatsDate ║ ╠═══════════════╬═══════════╬═══════════╣ ║ dbo.SomeTable ║ cx ║ NULL ║ ║ dbo.SomeTable ║ я ║ 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';
╔═══════════════╦═══════════╦═════════════════════ ════╗ ║ ObjectName ║ StatsName ║ StatsDate ║ ╠═══════════════╬═══════════╬═════════════════════ ════╣ ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║ ║ dbo.SomeTable ║ я ║ 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
столбцу:
╔═══════════════╦═══════════╦═════════════════════ ════╗ ║ ObjectName ║ StatsName ║ StatsDate ║ ╠═══════════════╬═══════════╬═════════════════════ ════╣ ║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║ ║ dbo.SomeTable ║ я ║ 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';
╔═══════════════╦═══════════╦═════════════════════ ════╗ ║ 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 ║ ╚═══════════════╩═══════════╩═════════════════════ ════╝
Как видите, единственный способ убедиться, что все статистические данные обновлены, это либо обновить каждую статистику вручную, либо обновить всю таблицу с помощью UPDATE STATISTICS (table);
.
ALTER INDEX ... REBUILD
либо UPDATE STATISTICS
оператора. Если сама таблица перестроена, обновляется только статистика кластерного индекса. К вашему сведению, первичный ключ и кластерный индекс не обязательно поддерживаются одним и тем же объектом индекса.
Страница документов Microsoft для статистики SQL Server гласит :
Такие операции, как перестройка, дефрагментация или реорганизация индекса, не изменяют распределение данных. Поэтому вам не нужно обновлять статистику после выполнения операций ALTER INDEX REBUILD, DBCC DBREINDEX, DBCC INDEXDEFRAG или ALTER INDEX REORGANIZE . Оптимизатор запросов обновляет статистику, когда вы перестраиваете индекс для таблицы или представления с помощью ALTER INDEX REBUILD или DBCC DBREINDEX, однако это обновление статистики является побочным продуктом повторного создания индекса. Оптимизатор запросов не обновляет статистику после операций DBCC INDEXDEFRAG или ALTER INDEX REORGANIZE.
REINDEX
обновляет статистику столбцов как побочный эффект перестройки индекса - вам не нужно обновлять статистику. Данные в таблице не меняются. Это те же самые данные, это только а) перемещение его местоположения на вращающемся блюде (когда страница реорганизуется), или б) размещение на другой странице (в случае перестроения). Итак: повторный индекс делает (некоторые) обновление статистики: нет необходимости делать это.