SQL Server では UPDATE STATISTICS を実行することでテーブルの統計情報を更新することができます。
UPDATE STATISTICS は次のクエリのようにテーブル名のみを指定することでテーブル内の全統計情報を更新することが可能です。
UPDATE STATISTICS LINEITEM
このような指定をした統計情報の更新を実行する場合、「列レベルの統計」が作成されている場合には考慮点があります。
テーブル名のみを指定した統計情報の更新の対象
テーブル名のみを指定した統計情報の更新は、ALL 相当の実行が行われます。
あまり指定する機会は少ないかもしれませんが、統計情報の更新は、ALL / COLUMNS / INDEX を指定することができ、どの統計情報を対象とするかを選択することができます。
ALL |COLUMNS |インデックス
すべての既存の統計、1 つ以上の列で作成された統計、またはインデックスに対して作成された統計を更新します。 いずれのオプションも指定されていない場合、
UPDATE STATISTICSステートメントは、テーブルまたはインデックス付きビューのすべての統計を更新します。
厳密には違うのですが、一般的なテーブルでは、次の統計情報が更新されるというイメージでよいかと思います。
- インデックス名で作成された統計情報: インデックス統計
- 統計情報の自動作成で作成された「_WA_Sys_xxxx」 の統計情報: 列統計
テーブル名を指定した統計情報更新時の考慮点
前述のとおり、テーブル名を指定した統計情報では、次の統計情報が更新されます。
- インデックス名で作成された統計情報: インデックス統計
- 統計情報の自動作成で作成された「_WA_Sys_xxxx」 の統計情報: 列統計
「1.」については、一般的な更新となるため新たな観点での考慮点はないのですが、「2.」については考慮が必要な観点があります。
「1.」については、次のようなクエリで統計情報を更新するために必要となるデータが取得されます。
インデックスの統計については、インデックスのキー項目でソート済みのデータが使用されるため、単純なデータ取得により統計に必要なデータの収集が行われます。
それでは「2.」の列統計についてはどうでしょうか。
列統計の更新では次のようなクエリが実行されます。
列統計については、インデックスが作られていない (ことが多い) ため、一度ソートを行い、統計情報に必要となるデータを取得する必要があります。
そのため、列統計の更新時にはソートコストが発生し、データサイズ / サンプリングレートによっては、大量のソート用メモリの確保が行われることがあります。
低サンプリング (サンプリング率を指定しない / RESAMPLE を小さい値で実施する) で実施する場合には、「TABLESAMPLE」が自動的に指定されるため、それほど速度は問題にならないのですが、「FULLSCAN」を指定した場合には注意が必要となります。
具体的には次のようなクエリとなります。
UPDATE STATISTICS LINEITEM WITH FULLSCAN
このクエリでは「インデックス統計」「列統計」の両統計が FULLSCAN により、更新されることになります。
インデックス統計についてはソート済みデータのため、オーバーヘッドは多少低いですが、列統計についてはソートコストが発生するため、かなりオーバーヘッドが多いです。(FULLSCAN を指定した場合、インデックス統計についてはソートコストは発生しませんが、全データのFULLSCANが発生しますので、こちらもそれなりに負荷が高い処理にはなりますが)
数億件のデータが格納されている場合、列レベルの統計を更新するのに数 10 分かかることがあります。
そのため、FULLSCAN を指定して統計情報を更新する場合、データサイズによっては、次のように指定したほうが良いケースがあります。
UPDATE STATISTICS LINEITEM WITH COLUMNS UPDATE STATISTICS LINEITEM WITH INDEX, FULLSCAN
列統計については、既定のサンプリングを指定し、インデックス統計については、FULLSCAN をするという指定となります。
このような指定をすることで単純にテーブルに対して FULLSCAN を指定するより、短時間で統計情報の更新を行うことができます。