再インデックスは統計を更新しますか?


43

この1週間、MS10775Aコースを実施してきましたが、トレーナーが確実に答えられなかった質問が1つあります。

再インデックスは統計を更新しますか?

私たちはオンラインで議論し、そうすることとしないことの両方を主張しました。


REINDEXインデックスを再構築する副作用として列統計が更新されることに注意してください。統計を更新する必要ありません。テーブル内のデータは変更されません。それは同じデータで、a)回転するプラッター上の位置を移動した(ページが再編成されたとき)、またはb)別のページに座った(再構築の場合)だけです。そのため、インデックスの再作成(一部の)統計情報を更新します。実行する必要はありません。
イアン・ボイド

回答:


51

統計の更新を気にするときは、次のことに注意してください(インデックスの再構築と統計の更新からコピー)(Benjamin Nevarez)

  1. デフォルトでは、UPDATE STATISTICSステートメントはテーブルのレコードのサンプルのみを使用します。を使用UPDATE STATISTICS WITH FULLSCANすると、テーブル全体がスキャンされます。

  2. デフォルトでは、UPDATE STATISTICSステートメントはインデックスとカラムの両方の統計を更新します。このCOLUMNSオプションを使用すると、列統計のみが更新されます。このINDEXオプションを使用すると、インデックス統計のみが更新されます。

  3. 使用してインデックスを再構築すると、テーブルがパーティション化されていない限りALTER INDEX … REBUILD使用と同等のインデックス統計も更新されます。その場合、統計はサンプリングのみです(SQL Server 2012以降に適用)。WITH FULLSCAN

  4. を使用しCREATE STATISTICSて手動で作成された統計はALTER INDEX ... REBUILD、などの操作によって更新されませんALTER TABLE ... REBUILDALTER 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║i║NULL║
║dbo.SomeTable║pk║NULL║
bo 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║i║NULL║
║dbo.SomeTable║pk║NULL║
bo 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║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';
╔===============╦==========╦==================== ====╗
║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);です。


@JeremyWeir-上記の質問に追加したばかりのサンプルコードからわかるように、更新される統計はALTER INDEX ... REBUILDUPDATE STATISTICSステートメントまたはステートメントのいずれかによって明示的に更新された統計のみです。テーブル自体が再構築される場合、クラスター化インデックスの統計のみが更新されます。参考までに、主キーとクラスター化インデックスは、必ずしも同じインデックスオブジェクトでサポートされているわけではありません。
マックスヴァーノン

5

SQL Serverの統計状態のMicrosoft Docsページ:

インデックスの再構築、デフラグ、または再編成などの操作は、データの分布を変更しません。したがって、ALTER INDEX REBUILD、DBCC DBREINDEX、DBCC INDEXDEFRAG、またはALTER INDEX REORGANIZE操作を実行した後、統計を更新する必要はありません。ALTER INDEX REBUILDまたはDBCC DBREINDEXを使用してテーブルまたはビューのインデックスを再構築すると、クエリオプティマイザーは統計を更新しますが、この統計の更新はインデックスの再作成の副産物です。クエリオプティマイザーは、DBCC INDEXDEFRAGまたはALTER INDEX REORGANIZE操作の後に統計を更新しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.