sys.dm_db_index_physical_stats (Transact-SQL)

指定したテーブルまたはビューのデータとインデックスに関する、サイズおよび断片化情報を返します。インデックスの場合、各パーティションの B ツリーのレベルごとに 1 行のデータが返されます。ヒープの場合、各パーティションの IN_ROW_DATA アロケーション ユニットごとに 1 行のデータが返されます。ラージ オブジェクト (LOB) データの場合、各パーティションの LOB_DATA アロケーション ユニットごとに 1 行のデータが返されます。テーブルに行オーバーフロー データが存在する場合、各パーティションの ROW_OVERFLOW_DATA アロケーション ユニットごとに 1 行のデータが返されます。アロケーション ユニットとパーティションの詳細については、「テーブルとインデックスのデータ構造のアーキテクチャ」を参照してください。

トピック リンク アイコンTransact-SQL 構文表記規則

構文

sys.dm_db_index_physical_stats ( 
    { database_id | NULL | 0 | DEFAULT }
  , { object_id | NULL | 0 | DEFAULT }
  , { index_id | NULL | 0 | -1 | DEFAULT }
  , { partition_number | NULL | 0 | DEFAULT }
  , { mode | NULL | DEFAULT }
)

引数

  • database_id | NULL | 0 | DEFAULT
    データベースの ID を指定します。database_id のデータ型は smallint です。有効な入力値は、データベースの ID 番号、NULL、0、または DEFAULT です。既定値は 0 です。このコンテキストでは、NULL、0、および DEFAULT は同じ値になります。

    SQL Server のインスタンスのすべてのデータベースに関する情報を返すには NULL を指定します。database_id に NULL を指定する場合は、object_id、index_id、および partition_number にも NULL を指定する必要があります。

    組み込み関数 DB_ID を指定できます。データベース名を指定しないで DB_ID を使用する場合、現在のデータベースの互換性レベルが 90 以上である必要があります。

  • object_id | NULL | 0 | DEFAULT
    インデックスがあるテーブルまたはビューのオブジェクト ID を指定します。object_id のデータ型は int です。

    有効な入力値は、テーブルおよびビューの ID 番号、NULL、0、または DEFAULT です。既定値は 0 です。このコンテキストでは、NULL、0、および DEFAULT は同じ値になります。

    NULL を指定すると、指定されたデータベース内にあるすべてのテーブルとビューに関する情報が返されます。object_id に NULL を指定する場合は、index_id および partition_number にも NULL を指定する必要があります。

  • index_id | 0 | NULL | -1 | DEFAULT
    インデックスの ID を指定します。index_id のデータ型は int です。有効な入力値は、インデックスの ID 番号、NULL、-1、または DEFAULT です。object_id がヒープの場合は、0 も有効です。既定値は -1 です。このコンテキストでは、NULL、-1、および DEFAULT は同じ値になります。

    NULL を指定すると、ベース テーブルまたはビューのすべてのインデックスに関する情報が返されます。index_id に NULL を指定する場合は、partition_number にも NULL を指定する必要があります。

  • partition_number | NULL | 0 | DEFAULT
    オブジェクト内のパーティション番号を指定します。partition_number のデータ型は int です。有効な入力値は、インデックスやヒープの partion_number、NULL、0、または DEFAULT です。既定値は 0 です。このコンテキストでは、NULL、0、および DEFAULT は同じ値になります。

    NULL を指定すると、所有するオブジェクトのすべてのパーティションに関する情報が返されます。

    partition_number は 1 から始まります。非パーティション インデックスまたはヒープでは、partition_number が 1 に設定されます。

  • mode | NULL | DEFAULT
    モードの名前を指定します。mode には統計の取得に使用されるスキャン レベルを指定します。mode のデータ型は sysname です。有効な入力値は DEFAULT、NULL、LIMITED、SAMPLED、DETAILED です。既定値 (NULL) は LIMITED です。

返されるテーブル

列名

データ型

説明

database_id

smallint

テーブルまたはビューのデータベース ID。

object_id

int

インデックスがあるテーブルまたはビューのオブジェクト ID。

index_id

int

インデックスのインデックス ID。

0 = ヒープ。

partition_number

int

所有するオブジェクト (テーブル、ビュー、インデックス) 内の 1 から始まるパーティション番号。

1 = パーティション分割されていないインデックスまたはヒープ。

index_type_desc

nvarchar(60)

インデックスの種類の説明。

HEAP

CLUSTERED INDEX

NONCLUSTERED INDEX

PRIMARY XML INDEX

SPATIAL INDEX

XML INDEX

alloc_unit_type_desc

nvarchar(60)

アロケーション ユニットの種類の説明。

IN_ROW_DATA

LOB_DATA

ROW_OVERFLOW_DATA

LOB_DATA アロケーション ユニットには、text、ntext、image、varchar(max)、nvarchar(max)、varbinary(max)、xml 型の列に格納されているデータが含まれます。詳細については、「データ型 (Transact-SQL)」を参照してください。

ROW_OVERFLOW_DATA アロケーション ユニットには、行外に出された varchar(n)、nvarchar(n)、varbinary(n)、sql_variant 型の列に格納されているデータが含まれます。詳細については、「8 KB を超える場合の行オーバーフロー データ」を参照してください。

index_depth

tinyint

インデックス レベルの数。

1 = ヒープ、LOB_DATA アロケーション ユニット、または ROW_OVERFLOW_DATA アロケーション ユニット。

index_level

tinyint

インデックスの現在のレベル。

インデックスのリーフ レベル、ヒープ、および LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは 0 になります。

非リーフ インデックス レベルでは 0 より大きい数になります。index_level はインデックスのルート レベルで最大になります。

インデックスの非リーフ レベルは、mode = DETAILED の場合にのみ処理されます。

avg_fragmentation_in_percent

float

インデックスの論理的な断片化、または IN_ROW_DATA アロケーション ユニットでのヒープのエクステントの断片化。

値はパーセンテージ (%) で表され、複数のファイルが考慮されます。論理的な断片化とエクステントの断片化の定義については、「解説」を参照してください。

LOB_DATA および ROW_OVERFLOW_DATA アロケーション ユニットでは 0 になります。

ヒープでは、mode = SAMPLED の場合、NULL になります。

fragment_count

bigint

IN_ROW_DATA アロケーション ユニットのリーフ レベルでのフラグメントの数。フラグメントの詳細については、「解説」を参照してください。

インデックスの非リーフ レベル、および LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは NULL になります。

ヒープでは、mode = SAMPLED の場合、NULL になります。

avg_fragment_size_in_pages

float

IN_ROW_DATA アロケーション ユニットのリーフ レベルにおける、フラグメントあたりのページの平均数。

インデックスの非リーフ レベル、および LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは NULL になります。

ヒープでは、mode = SAMPLED の場合、NULL になります。

page_count

bigint

インデックス ページまたはデータ ページの合計数。

インデックスでは、IN_ROW_DATA アロケーション ユニットに含まれる B ツリーの現在のレベルにおけるインデックス ページの合計数になります。

ヒープでは、IN_ROW_DATA アロケーション ユニットに含まれるデータ ページの合計数になります。

LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは、アロケーション ユニットに含まれる合計ページ数になります。

avg_page_space_used_in_percent

float

すべてのページで、使用可能なデータ ストレージ領域のうち使用されているパーセンテージ (%) の平均。

インデックスでは、IN_ROW_DATA アロケーション ユニットに含まれる B ツリーの現在のレベルでの平均になります。

ヒープでは、IN_ROW_DATA アロケーション ユニットに含まれるすべてのデータ ページの平均になります。

LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは、アロケーション ユニットに含まれるすべてのページの平均になります。

mode = LIMITED の場合は NULL です。

record_count

bigint

レコードの総数。

インデックスでは、IN_ROW_DATA アロケーション ユニットに含まれる B ツリーの現在のレベルにおけるレコードの合計数になります。

ヒープでは、IN_ROW_DATA アロケーション ユニットに含まれるレコードの合計数になります。

注意
ヒープでは、この関数から返されるレコード数が、ヒープに対して SELECT COUNT(*) を実行したときに返される行数と一致しない場合があります。これは、1 行に複数のレコードが含まれる場合があるためです。たとえば、更新の状況によっては、更新操作の結果として転送元レコードと転送先レコードが 1 つのヒープ行に含まれることがあります。また、大きな LOB 行のほとんどは、LOB_DATA ストレージ内で複数のレコードに分割されます。

LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは、アロケーション ユニット全体でのレコードの合計数になります。

mode = LIMITED の場合は NULL です。

ghost_record_count

bigint

アロケーション ユニットで、非実体クリーンアップ タスクによる削除の準備ができているゴースト レコードの数。

IN_ROW_DATA アロケーション ユニットに含まれるインデックスの非リーフ レベルでは 0 になります。

mode = LIMITED の場合は NULL です。

version_ghost_record_count

bigint

アロケーション ユニット内で、未処理のスナップショット分離トランザクションによって保持されているゴースト レコードの数。

IN_ROW_DATA アロケーション ユニットに含まれるインデックスの非リーフ レベルでは 0 になります。

mode = LIMITED の場合は NULL です。

min_record_size_in_bytes

int

最小レコード サイズ (バイト単位)。

インデックスでは、IN_ROW_DATA アロケーション ユニットに含まれる B ツリーの現在のレベルでの最小レコード サイズになります。

ヒープでは、IN_ROW_DATA アロケーション ユニットに含まれる最小レコード サイズになります。

LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは、アロケーション ユニット全体での最小レコード サイズになります。

mode = LIMITED の場合は NULL です。

max_record_size_in_bytes

int

最大レコード サイズ (バイト単位)。

インデックスでは、IN_ROW_DATA アロケーション ユニットに含まれる B ツリーの現在のレベルでの最大レコード サイズになります。

ヒープでは、IN_ROW_DATA アロケーション ユニットに含まれる最大レコード サイズになります。

LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは、アロケーション ユニット全体での最大レコード サイズになります。

mode = LIMITED の場合は NULL です。

avg_record_size_in_bytes

float

平均レコード サイズ (バイト単位)。

インデックスでは、IN_ROW_DATA アロケーション ユニットに含まれる B ツリーの現在のレベルでの平均レコード サイズになります。

ヒープでは、IN_ROW_DATA アロケーション ユニットに含まれる平均レコード サイズになります。

LOB_DATA または ROW_OVERFLOW_DATA アロケーション ユニットでは、アロケーション ユニット全体での平均レコード サイズになります。

mode = LIMITED の場合は NULL です。

forwarded_record_count

bigint

別のデータの場所への転送ポインターを持つ、ヒープ内の転送されたレコード数です (この状態は、更新中に、新しい行を格納できる十分なスペースが元の場所にない場合に発生します)。

ヒープの IN_ROW_DATA アロケーション ユニット以外のアロケーション ユニットでは NULL になります。

ヒープでは、mode = LIMITED の場合、NULL になります。

compressed_page_count

bigint

圧縮されたページ数です。

  • ヒープの場合、新しく割り当てられたページはページ圧縮されません。ヒープは、2 つの特殊な条件の下でページ圧縮されます。1 つはデータが一括インポートされた場合で、もう 1 つはヒープが再構築された場合です。ページ割り当ての原因となる通常の DML 操作ではページ圧縮されません。compressed_page_count の値が目標のしきい値を超えた場合は、ヒープを再構築してください。

  • クラスター化インデックスを含むテーブルの場合、compressed_page_count の値はページ圧縮の効果を示します。

説明

sys.dm_db_index_physical_stats 動的管理関数は、DBCC SHOWCONTIG ステートメントの代わりに使用できます。この動的管理関数には、CROSS APPLY および OUTER APPLY からの相関パラメーターを指定できません。

スキャン モード

関数が実行されるモードによって、関数で使用する統計データを取得するためのスキャンのレベルが決まります。mode は LIMITED、SAMPLED、DETAILED のいずれかになります。この関数は、ページ チェーンをスキャンすることにより、テーブルまたはインデックスの指定パーティションを構成するアロケーション ユニットを検索します。sys.dm_db_index_physical_stats には実行するモードに関係なく、インテント共有 (IS) テーブル ロックのみが必要です。ロックの詳細については、「ロック モード」を参照してください。

LIMITED モードは最も高速なモードで、スキャンするページ数は最小です。インデックスでは、B ツリーの親レベルのページ (リーフ レベルより上のページ) だけがスキャンされます。ヒープでは、関連付けられた PFS ページおよび IAM ページだけが調べられます。ヒープのデータ ページはスキャンされません。SQL Server 2005 では、LIMITED モードの場合、ヒープのすべてのページがスキャンされます。

LIMITED モードでは、データベース エンジン は B ツリーの非リーフ ページとヒープの IAM および PFS ページのみをスキャンするので、compressed_page_count は NULL です。compressed_page_count の推定値の取得には SAMPLED モードを使用します。compressed_page_count の実際の値を取得するには DETAILED モードを使用します。SAMPLED モードはインデックスまたはヒープの全ページの 1% をサンプルにした統計を返します。SAMPLED モードの結果は概数と見なす必要があります。インデックスまたはヒープのページが 10,000 ページに満たない場合は、SAMPLED モードの代わりに DETAILED モードが使用されます。

DETAILED モードではすべてのページがスキャンされ、すべての統計が返されます。

各モードで実行される処理は LIMITED、SAMPLED、DETAILED の順に増加し、それに応じて処理時間は遅くなります。テーブルまたはインデックスの断片化レベルのサイズをすばやく計測するには、LIMITED モードを使用します。LIMITED モードは最も高速で、インデックスの IN_ROW_DATA アロケーション ユニットにおける各非リーフ レベルの行は返されません。

システム関数によるパラメーター値の指定

Transact-SQL 関数 DB_ID および OBJECT_ID を使用して、database_id および object_id パラメーターの値を指定できます。ただし、これらの関数に無効な値を渡すと、意図しない結果が生じる可能性があります。たとえば、データベースまたはオブジェクト名が存在しないか、スペルが間違っていることが原因で見つからない場合は、どちらの関数も NULL を返します。sys.dm_db_index_physical_stats 関数では、NULL 値はすべてのデータベースまたはすべてのオブジェクトを指定するワイルドカード値として解釈されます。

また、OBJECT_ID 関数は、sys.dm_db_index_physical_stats 関数の呼び出し前に処理されるので、database_id で指定したデータベースではなく、現在のデータベースのコンテキストで評価されます。この動作により、OBJECT_ID 関数で NULL 値が返される場合があります。または、オブジェクト名が現在のデータベースのコンテキストと指定したデータベースの両方に存在する場合は、エラー メッセージが返されることがあります。次の例は、こうした意図しない結果を示すものです。

次の例では、master データベースのコンテキストで OBJECT_ID が評価されています。Person.Address が master に存在しないため、関数は NULL を返します。object_id に NULL が指定されると、データベース内のすべてのオブジェクトが返されます。無効なオブジェクトが指定された場合も、同様の結果が返されます。

USE master;
GO
SELECT * FROM sys.dm_db_index_physical_stats
    (DB_ID(N'AdventureWorks'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO

次の例では、現在のデータベース コンテキストと、sys.dm_db_index_physical_stats 関数の database_id パラメーターに指定されたデータベースの両方に存在する有効なオブジェクト名を指定した場合の結果を示します。OBJECT_ID によって返された ID 値が、指定されたデータベースのオブジェクトの ID 値と一致しないため、エラーが返されます。

CREATE DATABASE Test;
GO
USE Test;
GO
CREATE SCHEMA Person;
GO
CREATE Table Person.Address(c1 int);
GO
USE AdventureWorks2008R2;
GO
SELECT * FROM sys.dm_db_index_physical_stats
    (DB_ID(N'Test'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- Clean up temporary database.
DROP DATABASE Test;
GO

推奨事項

DB_ID または OBJECT_ID を使用する場合は、必ず有効な ID が返されるようにしてください。たとえば、OBJECT_ID を使用する場合は、OBJECT_ID(N'AdventureWorks2008R2.Person.Address') のように 3 部構成の名前を指定するか、関数で返される値を sys.dm_db_index_physical_stats 関数で使用する前にテストします。後の例 A と B は、データベース ID とオブジェクト ID を安全に指定する方法を示しています。

断片化の検出

断片化は、テーブルとテーブルに定義されたインデックスに対して、INSERT、UPDATE、DELETE ステートメントによるデータ変更が行われる過程で発生します。これらの変更は、テーブルとインデックスのすべての行に均等に分散されるわけではないので、時間が経つにつれ各ページのゆとりに差が生じることになります。このような断片化があるときに、クエリでテーブルのインデックスの一部または全部をスキャンしようとすると、余分なページの読み取りが必要になり、データの並列スキャンの妨げになります。

SQL Server 2008 では、SQL Server 2000 よりも断片化計算のアルゴリズムが正確になりました。その結果、断片化の値は以前より高いように見えます。たとえば SQL Server 2000 では、テーブルの 11 ページと 13 ページが同じエクステントにあり、12 ページがない場合、そのテーブルは断片化しているとは見なされません。一方 SQL Server 2008 では、この 2 つのページにアクセスするために 2 回の物理的な I/O 操作が必要になることから、このテーブルが断片化していると見なされます。

インデックスまたはヒープの断片化レベルは、avg_fragmentation_in_percent 列で確認できます。ヒープの場合、この列の値はヒープのエクステントの断片化を表します。インデックスの場合、この値はインデックスの論理的な断片化を表します。DBCC SHOWCONTIG とは異なり、どちらの場合の断片化計算アルゴリズムでも複数のファイルにまたがるストレージが考慮されており、正確な計算値が得られます。

論理的な断片化

これは、インデックスのリーフ ページでの順序が不正なページの割合です。順序が不正なページとは、インデックスに割り当てられている次の物理的なページと、現在のリーフ ページの次ページ ポインターが示すページが異なるページのことです。

エクステントの断片化

これは、ヒープのリーフ ページでの順序が不正なエクステントの割合です。順序が不正なエクステントとは、ヒープの現在のページを含むエクステントの物理的な位置が、前のページを含むエクステントの直後でない状態のエクステントを指します。

最大のパフォーマンスを得るには、avg_fragmentation_in_percent の値をできるだけ 0 に近くする必要があります。ただし、0 ~ 10% の値は許容範囲です。再構築、再構成、再作成など、断片化を解消するためのさまざまな手段を使用することによって、この値を下げることができます。インデックス内の断片化度を分析する方法の詳細については、「インデックスの再編成と再構築」を参照してください。

インデックスの断片化の解消

クエリのパフォーマンスに影響が出るほどインデックスが断片化している場合、断片化を解消するには 3 つの方法があります。

  • クラスター化インデックスを削除し、再作成する。

    クラスター化インデックスを再作成すると、データが再分配され、データ ページにデータが満たされます。ページのゆとりのレベルは、CREATE INDEX の FILLFACTOR オプションを使用して構成できます。この方法の短所は、削除と再作成が行われている間、インデックスがオフラインになることと、操作がアトミックであることです。インデックスの作成が中断されると、インデックスは再作成されません。詳細については、「CREATE INDEX (Transact-SQL)」を参照してください。

  • DBCC INDEXDEFRAG の代わりの ALTER INDEX REORGANIZE を使用して、インデックスのリーフ レベル ページを論理順序の順に並べ替える。これはオンライン操作のため、ステートメントの実行中もインデックスを使用できます。操作を中断しても、それまでに完了した作業は失われません。この方法の短所は、インデックスの再構築操作ほど、データの再構成が適切に行われず、統計も更新されないことです。

  • DBCC DBREINDEX の代わりの ALTER INDEX REBUILD を使用して、オンラインまたはオフラインでインデックスを再構築する。詳細については、「ALTER INDEX (Transact-SQL)」を参照してください。

断片化だけでは、インデックスを再構成または再構築する十分な理由にはなりません。断片化の影響は主に、インデックスのスキャン中にページの先行読み取りのスループットが減速することです。これは、応答時間の遅れの原因となります。断片化したテーブルまたはインデックスでのクエリのワークロードにスキャンが関係していない場合、ワークロードは主に単一参照のため、断片化を解消しても効果はありません。詳細については、Microsoft Web サイトを参照してください。

注意

DBCC SHRINKFILE または DBCC SHRINKDATABASE を実行した場合、圧縮操作中にインデックスが部分的または完全に移動すると、断片化が発生することがあります。このため、圧縮操作を実行する必要がある場合は、断片化の解消前に行ってください。

ヒープの断片化の解消

ヒープのエクステントの断片化を解消するには、テーブルにクラスター化インデックスを作成し、インデックスを削除します。これによって、クラスター化インデックスの作成中にデータが再分配されます。この操作では、データベースの空き領域の分布を考慮に入れて、可能な限り最適化も行われます。この後、ヒープを再作成するためにクラスター化インデックスを削除しても、データは移動せず、最適な状態が保たれます。この操作の実行方法については、「CREATE INDEX」および「DROP INDEX」を参照してください。

注記注意

テーブルでクラスター化インデックスを作成および削除すると、そのテーブルのすべての非クラスター化インデックスが 2 回再構築されます。

ラージ オブジェクト データの圧縮

既定では、ALTER INDEX REORGANIZE ステートメントを実行すると、ラージ オブジェクト (LOB) データを含むページが圧縮されます。LOB ページは空の場合でも割り当てを解除されないので、多くの LOB データまたは LOB 列が削除された場合は、このデータを圧縮することでディスク領域の使用が改善されます。

特定のクラスター化インデックスを再構成すると、そのクラスター化インデックスに含まれるすべての LOB 列が圧縮されます。非クラスター化インデックスを再構成すると、そのインデックス内で非キー列 (付加列) となっているすべての LOB 列が圧縮されます。ステートメントで ALL を指定した場合は、指定したテーブルまたはビューに関連付けられているすべてのインデックスが再構成されます。さらに、クラスター化インデックス、基になるテーブル、または付加列を含む非クラスター化インデックスに関連付けられているすべての LOB 列も圧縮されます。

ディスク領域の使用状況の評価

avg_page_space_used_in_percent 列には、ページのゆとりが示されます。ディスク領域の使用を最適にするには、ランダムな挿入があまり行われないインデックスの場合はこの値を 100% に近づけます。一方、ランダムな挿入が多く行われ、いっぱいになったページが多いインデックスの場合はページ分割数が増えるため、断片化が大きくなります。したがって、ページ分割数を減らすには、値を 100% よりも少なくする必要があります。FILLFACTOR オプションを指定してインデックスを再構築すると、ページのゆとりをインデックスのクエリ パターンに合わせて変更できます。FILL FACTOR の詳細については、「FILL FACTOR」を参照してください。また、ALTER INDEX REORGANIZE は最後に指定された FILLFACTOR までページが埋まるよう、インデックスを圧縮します。これにより、avg_space_used_in_percent の値は増加します。ALTER INDEX REORGANIZE はページのゆとりを調整できないことに注意してください。代わりに、インデックスの再構築を実行する必要があります。

インデックスのフラグメントの評価

フラグメントは、1 つのアロケーション ユニットに含まれる同一ファイル内の、物理的に連続するリーフ ページで構成されます。1 つのインデックスには少なくとも 1 つのフラグメントが含まれます。インデックスが持つことのできるフラグメントの最大数は、インデックスのリーフ レベルのページ数と同じです。フラグメントが大きいほど、同じ数のページの読み取りに必要なディスクの I/O が少なくなります。したがって、avg_fragment_size_in_pages 値が大きいほど、範囲スキャンのパフォーマンスは向上します。avg_fragment_size_in_pages の値と avg_fragmentation_in_percent の値は、互いに反比例します。したがって、インデックスを再構築または再構成すると、断片化が解消し、フラグメントのサイズが大きくなります。

権限

次の権限が必要です。

  • データベース内の指定したオブジェクトに対する CONTROL 権限。

  • オブジェクトのワイルドカード @object_id= NULL を使用して、特定のデータベース内にあるすべてのオブジェクトに関する情報を返す VIEW DATABASE STATE 権限。

  • データベースのワイルドカード @database_id = NULL を使用して、すべてのデータベースに関する情報を返す VIEW SERVER STATE 権限。

VIEW DATABASE STATE 権限を許可すると、特定のオブジェクトに対して CONTROL 権限が拒否されていたとしても、データベース内のすべてのオブジェクトを取得することができます。

VIEW DATABASE STATE 権限を拒否すると、特定のオブジェクトに対する CONTROL 権限が許可されていたとしても、そのデータベース内のどのオブジェクトも取得できません。また、データベースのワイルドカード @database_id=NULL を指定した場合、データベースは省略されます。

詳細については、「動的管理ビューおよび関数 (Transact-SQL)」を参照してください。

使用例

A. 指定したテーブルの情報を返す

次の例では、AdventureWorks2008R2 データベース内にある Person.Address テーブルのすべてのインデックスとパーティションについて、サイズと断片化の統計を返します。パフォーマンスを向上させ、返される統計を制限するために、スキャン モードは 'LIMITED' に設定されています。このクエリを実行するには、少なくとも Person.Address テーブルに対する CONTROL 権限が必要です。

DECLARE @db_id SMALLINT;
DECLARE @object_id INT;

SET @db_id = DB_ID(N'AdventureWorks2008R2');
SET @object_id = OBJECT_ID(N'AdventureWorks2008R2.Person.Address');

IF @db_id IS NULL
BEGIN;
    PRINT N'Invalid database';
END;
ELSE IF @object_id IS NULL
BEGIN;
    PRINT N'Invalid object';
END;
ELSE
BEGIN;
    SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , 'LIMITED');
END;
GO

B. ヒープに関する情報を返す

次の例では、AdventureWorks2008R2 データベースのヒープ dbo.DatabaseLog に関するすべての統計を返します。テーブルには LOB データが含まれているため、ヒープのデータ ページを格納している IN_ROW_ALLOCATION_UNIT アロケーション ユニットの行だけではなく、LOB_DATA アロケーション ユニットの行も返されます。このクエリを実行するには、少なくとも dbo.DatabaseLog テーブルに対する CONTROL 権限が必要です。

DECLARE @db_id SMALLINT;
DECLARE @object_id INT;
SET @db_id = DB_ID(N'AdventureWorks2008R2');
SET @object_id = OBJECT_ID(N'AdventureWorks2008R2.dbo.DatabaseLog');
IF @object_id IS NULL 
BEGIN;
    PRINT N'Invalid object';
END;
ELSE
BEGIN;
    SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, 0, NULL , 'DETAILED');
END;
GO

C. すべてのデータベースに関する情報を返す

次の例では、すべてのパラメーターにワイルドカード NULL を指定して、SQL Server インスタンス内のすべてのテーブルとインデックスに関する統計を返します。このクエリを実行するには、VIEW SERVER STATE 権限が必要です。

SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL);
GO

D. sys.dm_db_index_physical_stats をスクリプトで使用してインデックスを再構築または再構成する

次の例では、平均断片化が 10% を超えるデータベース内のすべてのパーティションを、自動的に再構成または再構築します。このクエリを実行するには、VIEW DATABASE STATE 権限が必要です。この例では、データベース名を指定せずに DB_ID を 1 番目のパラメーターとして指定しています。現在のデータベースの互換性レベルが 80 以下になっているとエラーが発生します。このエラーを解決するには、DB_ID() を有効なデータベース名で置き換えます。データベースの互換性レベルの詳細については、「sp_dbcmptlevel (Transact-SQL)」を参照してください。

-- Ensure a USE <databasename> statement has been executed first.
SET NOCOUNT ON;
DECLARE @objectid int;
DECLARE @indexid int;
DECLARE @partitioncount bigint;
DECLARE @schemaname nvarchar(130); 
DECLARE @objectname nvarchar(130); 
DECLARE @indexname nvarchar(130); 
DECLARE @partitionnum bigint;
DECLARE @partitions bigint;
DECLARE @frag float;
DECLARE @command nvarchar(4000); 
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function 
-- and convert object and index IDs to names.
SELECT
    object_id AS objectid,
    index_id AS indexid,
    partition_number AS partitionnum,
    avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0;

-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;

-- Open the cursor.
OPEN partitions;

-- Loop through the partitions.
WHILE (1=1)
    BEGIN;
        FETCH NEXT
           FROM partitions
           INTO @objectid, @indexid, @partitionnum, @frag;
        IF @@FETCH_STATUS < 0 BREAK;
        SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)
        FROM sys.objects AS o
        JOIN sys.schemas as s ON s.schema_id = o.schema_id
        WHERE o.object_id = @objectid;
        SELECT @indexname = QUOTENAME(name)
        FROM sys.indexes
        WHERE  object_id = @objectid AND index_id = @indexid;
        SELECT @partitioncount = count (*)
        FROM sys.partitions
        WHERE object_id = @objectid AND index_id = @indexid;

-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
        IF @frag < 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';
        IF @frag >= 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
        IF @partitioncount > 1
            SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS nvarchar(10));
        EXEC (@command);
        PRINT N'Executed: ' + @command;
    END;

-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;

-- Drop the temporary table.
DROP TABLE #work_to_do;
GO

E. sys.dm_db_index_physical_stats を使用して、ページ圧縮されたページの数を表示する

次の例では、行とページが圧縮されているページと、ページ数の合計とを対比して表示します。この情報を使用して、インデックスまたはテーブルに対して圧縮がどの程度貢献しているかを調べることができます。

SELECT o.name,
    ips.partition_number,
    ips.index_type_desc,
    ips.record_count, ips.avg_record_size_in_bytes,
    ips.min_record_size_in_bytes,
    ips.max_record_size_in_bytes,
    ips.page_count, ips.compressed_page_count
FROM sys.dm_db_index_physical_stats ( DB_ID(), NULL, NULL, NULL, 'DETAILED') ips
JOIN sys.objects o on o.object_id = ips.object_id
ORDER BY record_count DESC;

F. SAMPLED モードで sys.dm_db_index_physical_stats を使用する

次の例では、SAMPLED モードによって DETAILED モードの結果と異なる概数がどのように返されるかを示しています。

CREATE TABLE t3 (col1 int PRIMARY KEY, col2 varchar(500)) WITH(DATA_COMPRESSION = PAGE);
GO
BEGIN TRAN
DECLARE @idx int = 0;
WHILE @idx < 1000000
BEGIN
    INSERT INTO t3 (col1, col2) 
    VALUES (@idx, 
    REPLICATE ('a', 100) + CAST (@idx as varchar(10)) + REPLICATE ('a', 380))
    SET @idx = @idx + 1
END
COMMIT;
GO
SELECT page_count, compressed_page_count, forwarded_record_count, * 
FROM sys.dm_db_index_physical_stats (db_id(), 
    object_id ('t3'), null, null, 'SAMPLED');
SELECT page_count, compressed_page_count, forwarded_record_count, * 
FROM sys.dm_db_index_physical_stats (db_id(), 
    object_id ('t3'), null, null, 'DETAILED');