回答:
統計の更新を気にするときは、次のことに注意してください(インデックスの再構築と統計の更新からコピー)(Benjamin Nevarez)
デフォルトでは、UPDATE STATISTICS
ステートメントはテーブルのレコードのサンプルのみを使用します。を使用UPDATE STATISTICS WITH FULLSCAN
すると、テーブル全体がスキャンされます。
デフォルトでは、UPDATE STATISTICS
ステートメントはインデックスとカラムの両方の統計を更新します。このCOLUMNS
オプションを使用すると、列統計のみが更新されます。このINDEX
オプションを使用すると、インデックス統計のみが更新されます。
使用してインデックスを再構築すると、テーブルがパーティション化されていない限り、ALTER INDEX … REBUILD
使用と同等のインデックス統計も更新されます。その場合、統計はサンプリングのみです(SQL Server 2012以降に適用)。WITH FULLSCAN
を使用し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║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);
です。
ALTER INDEX ... REBUILD
、UPDATE STATISTICS
ステートメントまたはステートメントのいずれかによって明示的に更新された統計のみです。テーブル自体が再構築される場合、クラスター化インデックスの統計のみが更新されます。参考までに、主キーとクラスター化インデックスは、必ずしも同じインデックスオブジェクトでサポートされているわけではありません。
SQL Serverの統計状態のMicrosoft Docsページ:
インデックスの再構築、デフラグ、または再編成などの操作は、データの分布を変更しません。したがって、ALTER INDEX REBUILD、DBCC DBREINDEX、DBCC INDEXDEFRAG、またはALTER INDEX REORGANIZE操作を実行した後、統計を更新する必要はありません。ALTER INDEX REBUILDまたはDBCC DBREINDEXを使用してテーブルまたはビューのインデックスを再構築すると、クエリオプティマイザーは統計を更新しますが、この統計の更新はインデックスの再作成の副産物です。クエリオプティマイザーは、DBCC INDEXDEFRAGまたはALTER INDEX REORGANIZE操作の後に統計を更新しません。
REINDEX
インデックスを再構築する副作用として列統計が更新されることに注意してください。統計を更新する必要はありません。テーブル内のデータは変更されません。それは同じデータで、a)回転するプラッター上の位置を移動した(ページが再編成されたとき)、またはb)別のページに座った(再構築の場合)だけです。そのため、インデックスの再作成は(一部の)統計情報を更新します。実行する必要はありません。