実行計画を“読む力”がSQL最適化の第一歩
SQL Serverの実行計画(Execution Plan)は、クエリがどのような手順でデータを取得・結合・集約しているかを示す設計図です。
パフォーマンス問題の多くはSQL構文そのものよりも、最適化の失敗や統計情報のずれによって生じます。
本記事では、実行計画の基礎から代表的なオペレーターの読み方、そして実務でのチューニング手法までを体系的に解説します。
目次
第1章 実行計画とは何か
実行計画は、SQL Serverのクエリオプティマイザが最適と判断した処理手順を示す情報です。
テーブルスキャン・インデックスシーク・結合順序・演算コストなどが視覚化され、チューニングの出発点となります。
- 推定実行計画:クエリ解析段階で想定される処理経路を示す(実行前に確認可)。
- 実際の実行計画:実行時の実測データ(行数・コスト・I/O等)を含む。
パフォーマンス分析では両方を比較することで、統計情報のずれや実際のデータ量との乖離を特定します。
第2章 実行計画の表示と種類(推定/実際)
実行計画はSQL Server Management Studio(SSMS)やT-SQLコマンドで取得できます。
-- 推定実行計画を表示(クエリ実行なし)
SET SHOWPLAN_XML ON;
GO
SELECT * FROM Sales.SalesOrderHeader WHERE CustomerID = 11000;
GO
SET SHOWPLAN_XML OFF;
-- 実際の実行計画を表示(実行あり)
SET STATISTICS XML ON;
GO
SELECT * FROM Sales.SalesOrderHeader WHERE CustomerID = 11000;
GO
SET STATISTICS XML OFF;
SSMSでは、ツールバーの「実際の実行計画を含めて実行」ボタンを押すことで視覚的に確認できます。
オペレーターの矢印が太いほど処理量(行数)が多く、パフォーマンスボトルネックの手掛かりになります。
第3章 主要オペレーターの読み方
実行計画の各アイコン(オペレーター)は、SQL Serverがどのようにデータを処理しているかを示します。代表的なものを以下にまとめます。
| オペレーター | 意味 | 主な改善策 |
|---|---|---|
| Table Scan | インデックスを使わず全件読み込み | WHERE句の列にインデックス作成 |
| Index Seek | インデックスを利用した効率的検索 | 統計情報最新化で最適計画維持 |
| Nested Loops | 外側ループごとに内側検索(少量結合向き) | 小テーブル側にインデックスを付与 |
| Hash Match | ハッシュテーブルを使う結合(大規模データ向き) | 適切な結合条件で不要ハッシュを防止 |
| Sort | ソート操作。ORDER BYやGROUP BYで発生 | インデックス順序で回避可能 |
第4章 実行計画の分析ポイント
実行計画を読む際のチェックポイントは次の通りです。
- 実行コスト:最もコストが高いオペレーターを特定。
- 行数の乖離:推定行数と実際の行数が大きく異なる箇所を確認。
- 結合順序:小テーブル→大テーブルの順が理想。
- I/O負荷:テーブルスキャン・ソート・ハッシュの過多に注意。
-- 実際の実行計画で行数の乖離をチェック
SELECT qs.total_logical_reads, qs.total_elapsed_time, st.text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
ORDER BY qs.total_elapsed_time DESC;
特に、Estimated Number of Rows と Actual Number of Rows の差が大きい場合は統計情報やインデックスの見直しが必要です。
第5章 SQLチューニングの基本アプローチ
- インデックス設計:WHERE句・JOIN句の列を分析し、カバリングインデックスを検討。
- 不要なSELECT:不要列の読み込みを削減(SELECT * は避ける)。
- 結合方法の見直し:結合順序とタイプ(Nested/Hash/Merge)を比較検証。
- サブクエリの簡略化:CTEやJOINで置き換え可能なら単純化。
-- 実行計画を変えるヒント句の例
SELECT *
FROM Orders o
INNER JOIN Customers c ON o.CustomerID = c.CustomerID
OPTION (HASH JOIN); -- 明示的に結合手法を指定
ヒント句は一時的な回避策として有効ですが、統計やインデックスの改善が根本的な解決になります。
第6章 統計情報とインデックス最適化
SQL Serverのクエリ最適化は、統計情報(各列のデータ分布)を基に実行計画を生成します。
統計が古いと推定行数がずれ、誤った実行計画が選択されます。
-- 統計情報の更新
UPDATE STATISTICS Sales.SalesOrderHeader;
-- すべての統計を自動更新
EXEC sp_updatestats;
また、断片化したインデックスはスキャンコストを増大させます。
-- インデックスの断片化を確認
SELECT
dbschemas.[name] as SchemaName,
dbtables.[name] as TableName,
dbindexes.[name] as IndexName,
indexstats.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
JOIN sys.tables dbtables ON dbtables.[object_id] = indexstats.[object_id]
JOIN sys.schemas dbschemas ON dbtables.[schema_id] = dbschemas.[schema_id]
JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
AND indexstats.index_id = dbindexes.index_id
WHERE indexstats.avg_fragmentation_in_percent > 20;
断片化率が高い場合は ALTER INDEX ... REBUILD または REORGANIZE で再構築します。
まとめ:実行計画を味方にする習慣を持とう
SQL Serverの実行計画は、性能問題の原因を最短で突き止めるための“地図”です。
テーブルスキャン・行数乖離・インデックス不備といったサインを見逃さず、定期的に分析・統計更新を行うことで、安定したパフォーマンスを維持できます。
実行計画を読む習慣をつけることが、SQLチューニングの最大の武器になります。
参考リンク(公式ドキュメント)

0 件のコメント:
コメントを投稿