2026年2月13日金曜日

SQL Server 統計情報(Statistics)の仕組みと最適化|実行計画精度の要・統計の仕組みと更新戦略

実行計画の精度は“統計”で決まる

SQL Serverの実行計画は、クエリ最適化エンジンが推定行数や分布情報をもとに最適なアクセス方法を選ぶことで生成されます。 その根拠となるデータが統計情報(Statistics)です。
統計が古い、または偏っていると推定行数がズレ、誤ったインデックス選択やプラン変更が起こります。
この記事では、統計情報の仕組み・更新・最適化方法を、実務に基づいて整理します。

目次

第1章 統計情報とは何か

統計情報(Statistics)は、テーブルやインデックス内のデータ分布を記録したメタ情報です。 クエリ最適化エンジンはこの情報をもとに「どのインデックスを使うか」「結合順をどうするか」を決定します。

  • 行数・重複度・NULL値の割合
  • カラムの代表値・ヒストグラム分布
  • 平均・最大・最小の値範囲

統計は「インデックス作成時」や「クエリ最初実行時(AUTO_CREATE_STATISTICS=ONの場合)」に自動生成されます。

第2章 統計情報の構造と内容

統計情報は主に2つの要素で構成されます。

  • ヘッダー情報:最終更新日時・行数・サンプル率など
  • ヒストグラム:値の分布を最大200ステップで保持(カラムの選択性を反映)
-- 統計の詳細確認
DBCC SHOW_STATISTICS ('dbo.Sales', 'IX_Sales_Date');

出力には次の3つの結果セットが含まれます:

  1. 統計ヘッダー
  2. 密度ベクトル(列の重複率)
  3. ヒストグラム(データ分布)

ヒストグラムは最大200分割され、クエリオプティマイザはここから行数を推定します。

第3章 自動統計更新の仕組みと注意点

SQL Serverは既定で統計情報を自動更新します(AUTO_UPDATE_STATISTICS = ON)。 ただし、この更新は「しきい値を超えた変更」があったときのみ行われます。

しきい値の概要(既定動作):

  • テーブル行数 < 500:変更が20%以上
  • テーブル行数 ≥ 500:変更が 500 + 0.2 × N 行を超えた場合

ただし大規模テーブルでは更新頻度が低くなり、推定行数が大きくずれることがあります。

-- 自動統計更新設定確認
SELECT name, is_auto_update_stats_on
FROM sys.databases;

-- 更新設定の有効化
ALTER DATABASE SalesDB SET AUTO_UPDATE_STATISTICS ON;

統計更新はクエリ実行時に同期的に行われるため、実行遅延の原因になる場合があります。 その場合は非同期更新(ASYNC)を検討します。

ALTER DATABASE SalesDB SET AUTO_UPDATE_STATISTICS_ASYNC ON;

第4章 手動更新と最適な運用タイミング

手動で統計情報を更新することで、最適化の精度を確実に高めることができます。

-- テーブル単位の統計更新
UPDATE STATISTICS dbo.Sales;

-- インデックス指定で更新
UPDATE STATISTICS dbo.Sales IX_Sales_Date WITH FULLSCAN;

-- データベース全体を更新
EXEC sp_updatestats;

FULLSCANを指定すると全件サンプリングを行いますが、負荷が高いため夜間メンテナンスでの実行が推奨されます。 定期メンテナンスプラン(IT0030)で自動化するのが実務的です。

第5章 統計の確認・分析方法

統計情報の状態は、システムビューからも確認できます。

-- 統計の更新日時を一覧表示
SELECT 
    OBJECT_NAME(object_id) AS TableName,
    name AS StatName,
    STATS_DATE(object_id, stats_id) AS LastUpdated
FROM sys.stats
ORDER BY LastUpdated DESC;

また、統計対象カラムやサンプリング率も確認可能です。

SELECT 
    OBJECT_NAME(s.object_id) AS TableName,
    s.name AS StatName,
    c.name AS ColumnName
FROM sys.stats_columns sc
JOIN sys.stats s ON sc.object_id = s.object_id AND sc.stats_id = s.stats_id
JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id
WHERE OBJECTPROPERTY(s.object_id, 'IsUserTable') = 1;

第6章 ベストプラクティスとチューニング指針

  • 1. 定期的に更新: 週次〜月次で sp_updatestats を実行。
  • 2. 重要テーブルはFULLSCAN: トラフィックの多い基幹テーブルは完全スキャンで精度保証。
  • 3. 統計を削除しない: Query Storeや最適化履歴に悪影響を与える。
  • 4. インデックス統計と列統計を区別: クエリパターンに応じてカスタム統計も有効。
  • 5. 自動更新はASYNC+手動併用: 実行中の負荷を避けつつ精度を維持。

統計の更新タイミングを監視ジョブ(IT0029参照)と組み合わせることで、 「古い統計を自動検知→更新」まで自律運用が可能です。

まとめ:統計を制する者が実行計画を制す

SQL Serverにおける実行計画の精度は、統計情報の鮮度と正確さに大きく依存します。 古い統計は推定行数のズレを生み、誤ったプランや不安定な性能の原因となります。 Query Store(IT0032)で検出した性能劣化は、統計更新で解決するケースが非常に多いです。 定期更新・可視化・自動化を組み合わせ、安定した最適化環境を維持しましょう。

参考リンク(公式ドキュメント)

SQL Server 解説用イメージ

0 件のコメント:

コメントを投稿