Переиндексирует ли обновление статистики?

43

Я проходил курс MS10775A на прошлой неделе, и возник вопрос, на который тренер не смог ответить надежно:

Обновляет ли реиндекс статистику?

Мы нашли обсуждения в Интернете, утверждая, что это так, а что нет.

Тор Эрик
источник
Полезно отметить, что REINDEXобновляет статистику столбцов как побочный эффект перестройки индекса - вам не нужно обновлять статистику. Данные в таблице не меняются. Это те же самые данные, это только а) перемещение его местоположения на вращающемся блюде (когда страница реорганизуется), или б) размещение на другой странице (в случае перестроения). Итак: повторный индекс делает (некоторые) обновление статистики: нет необходимости делать это.
Ян Бойд

Ответы:

51

Когда вы заботитесь об обновлении статистики, вы можете помнить следующее (скопировано из « Перестроение индексов против обновления статистики» (Бенджамин Неварез)

  1. По умолчанию UPDATE STATISTICSоператор использует только образец записей таблицы. Использование UPDATE STATISTICS WITH FULLSCANбудет сканировать всю таблицу.

  2. По умолчанию UPDATE STATISTICSоператор обновляет статистику индекса и столбца. Использование этой COLUMNSопции будет обновлять только статистику столбцов. Использование этой INDEXопции будет обновлять только статистику индекса.

  3. Перестройка индекса , например, с использованием ALTER INDEX … REBUILD, также обновит статистику индекса с использованием эквивалента использования, WITH FULLSCAN если таблица не секционирована, и в этом случае статистика выбирается только (применяется к SQL Server 2012 и более поздним версиям).

  4. Статистические данные, которые были созданы вручную CREATE STATISTICS, не обновляются никакими ALTER INDEX ... REBUILDоперациями, в том числе ALTER TABLE ... REBUILD. ALTER TABLE ... REBUILDобновляет статистику для кластеризованного индекса, если он определен в перестраиваемой таблице.

  5. Реорганизация индекса , например использование 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);.

MicSim
источник
@JeremyWeir - как вы можете видеть из примера кода, который я только что добавил к вопросу выше, обновляются только статистические данные, которые явно обновляются с помощью либо оператора, ALTER INDEX ... REBUILDлибо UPDATE STATISTICSоператора. Если сама таблица перестроена, обновляется только статистика кластерного индекса. К вашему сведению, первичный ключ и кластерный индекс не обязательно поддерживаются одним и тем же объектом индекса.
Макс Вернон
5

Страница документов Microsoft для статистики SQL Server гласит :

Такие операции, как перестройка, дефрагментация или реорганизация индекса, не изменяют распределение данных. Поэтому вам не нужно обновлять статистику после выполнения операций ALTER INDEX REBUILD, DBCC DBREINDEX, DBCC INDEXDEFRAG или ALTER INDEX REORGANIZE . Оптимизатор запросов обновляет статистику, когда вы перестраиваете индекс для таблицы или представления с помощью ALTER INDEX REBUILD или DBCC DBREINDEX, однако это обновление статистики является побочным продуктом повторного создания индекса. Оптимизатор запросов не обновляет статистику после операций DBCC INDEXDEFRAG или ALTER INDEX REORGANIZE.

б сторона
источник