こんにちは!
SQLのパフォーマンスが思うように出ない…。「このクエリ、なんでこんなに遅いんだ!?」と頭を抱えた経験、エンジニアなら一度はありますよね。その謎を解き明かすための最強の武器、それが「実行計画」です!
実行計画は、いわばOracleデータベースがSQLをどのように実行するかを示した「作戦書」。これを読み解くことができれば、パフォーマンス問題の根本原因を突き止め、劇的な改善へと導くことができます。
私自身、実行計画と向き合うことで、数々のパフォーマンス問題を解決し、エンジニアとして大きく成長することができました。
今回は、そんな私の経験も踏まえ、Oracleの実行計画の取得方法と、パフォーマンスチューニングに欠かせない見方のポイントを、世界一分かりやすく、そして情熱的に解説していきます!この記事を読めば、あなたもDBの気持ちがわかるエンジニアへの第一歩を踏み出せるはずです!
実行計画とは?なぜそんなに重要なの?
実行計画とは、あなたが書いたSQL文をOracleが受け取った後、「どのテーブルからデータを読み込み」「どのインデックスを使い」「どのようにテーブルを結合するか」といった、具体的な処理の手順を示した設計図のことです。
なぜこれが重要なのでしょうか?
それは、同じ結果を返すSQLでも、実行計画が違えばパフォーマンスが天と地ほど変わるからです。
例えば、「東京都に住む佐藤さん」を探すケースを考えてみましょう。
- 非効率な方法: 日本中の人々の名簿を最初から最後まで1ページずつ全部めくって探す。
- 効率的な方法: まず「東京都」の索引を引き、次に「さ行」の索引を引いて探す。
どちらが速いかは一目瞭然ですよね。SQLの世界でも全く同じことが起こっています。非効率な「全件スキャン(FULL TABLE SCAN)」を行っているSQLを、効率的な「索引スキャン(INDEX SCAN)」に変えるだけで、数時間かかっていた処理が数秒で終わるなんてことも珍しくありません。
実行計画は、あなたのSQLが前者のような非効率な動きをしていないかを確認するための、唯一無二の「羅針盤」なのです!
実行計画の取得方法【現場で使う3つの神器】
それでは、早速実行計画を取得する方法を見ていきましょう!現場で私がよく使う、強力な3つの方法をご紹介します。
EXPLAIN PLAN FOR:最も手軽な未来予測
これは、SQLを実際に実行することなく、Oracleが「もしこのSQLを実行したら、こんな計画を立てるよ」という未来の実行計画を教えてくれるコマンドです。
開発中に「このSQL、インデックス使ってくれるかな?」とサクッと確認したいときに非常に便利です。
使い方
まず、EXPLAIN PLAN FORに続けて、調査したいSQL文を実行します。
EXPLAIN PLAN FOR
SELECT * FROM employees WHERE employee_id = 100;
これだけでは何も表示されません。次に、以下のSQLを実行して、生成された実行計画を表示します。
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
実行結果(例)
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1293343999
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 87 | 1 |
| 1 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 1 | 87 | 1 |
|* 2 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPLOYEE_ID"=100)
この結果の見方は後ほど詳しく解説します!
AUTOTRACE:実行と同時に答え合わせ
SQL*PlusやSQL Developerなどのツールで使える機能で、SQLの実行結果と同時に、実際の実行計画や統計情報(どれくらいのI/Oがあったかなど)を表示してくれます。
開発環境でパフォーマンスを計測しながらSQLを調整していく際に、これ以上ないほど頼りになる相棒です!
使い方
以下のコマンドを実行してから、SQLを流すだけです。
-- 実行計画だけ表示
SET AUTOTRACE ON EXPLAIN;
-- 実行計画と統計情報を表示(おすすめ!)
SET AUTOTRACE TRACEONLY;
-- AUTOTRACEをオフにする
SET AUTOTRACE OFF;
例えば、SET AUTOTRACE TRACEONLY;を実行した後にSELECT * FROM employees WHERE employee_id = 100;を投げると、クエリの結果は表示されずに、実行計画と詳細な統計情報が表示されます。
V$SQL_PLAN:本番環境の真実を暴く
これは、Oracleが過去に実行したSQLの実行計画が格納されている「V$ビュー」という特別なテーブルです。
「本番環境で昨日から特定の処理が遅いんだけど…」といった場合に、実際に使われた実行計画を後から確認できるため、原因調査の強力な武器になります。
使い方
まず、遅いSQLのSQL_IDを特定する必要があります。(V$SQLなどから探します)SQL_IDがわかれば、以下のSQLで実行計画を取得できます。
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('SQLのIDをここに入れる'));
※ DISPLAY_AWR を使うには別途ライセンス(Oracle Diagnostics Pack)が必要な場合があります。
SQL_IDさえわかれば、過去に実行されたSQLの真実の姿を暴き出すことができるのです。
実行計画の見方【ここがキモ!3つのポイント】
さあ、いよいよ実行計画の解読方法です!一見すると暗号のようですが、ポイントさえ押さえれば誰でも読めるようになります。絶対に押さえるべきは以下の3つです!
Operation(操作内容):何をしているか?Cost(コスト):どれくらい重い処理か?Rows(カーディナリティ):何件のデータを扱う想定か?
先ほどのEXPLAIN PLANの結果をもう一度見てみましょう。
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 87 | 1 |
| 1 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 1 | 87 | 1 |
|* 2 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 |
--------------------------------------------------------------------------------
ポイント1:Operation – 処理の核心を読む!
Operation列は、Oracleが何をしているかを示します。インデントが最も深いところから上に向かって処理が実行されるとイメージしてください。この例では、Id=2 → Id=1 → Id=0 の順です。
INDEX UNIQUE SCAN(Id=2):EMP_EMP_ID_PKというユニークインデックスを使って、データを1件スキャン(検索)しています。これは非常に効率的な操作です!TABLE ACCESS BY INDEX ROWID(Id=1): インデックスで見つけたROWID(データの住所のようなもの)を使って、EMPLOYEESテーブルから実際のデータを取得しています。SELECT STATEMENT(Id=0): 最終的な結果を返しています。
一方で、パフォーマンス問題でよく見かけるのがTABLE ACCESS FULLです。これは「全件スキャン」を意味し、テーブルのデータを最初から最後まで全て読み込む操作です。巨大なテーブルでこれが出現したら、インデックスが効いていない可能性を疑いましょう!
ポイント2:Cost – 処理の重さを見極める!
Costは、Oracleが見積もった処理の重さ(負荷)です。この値が小さいほど効率的な実行計画であると言えます。
SQLチューニングは、このCost値をいかに小さくするか、というゲームでもあります。複数のSQL案で迷ったら、まずはCostを比較してみるのが良いでしょう。
ポイント3:Rows – 見積もりの精度を確認!
Rowsは、Oracleが「この操作で、これくらいの行数が返ってくるだろう」と予測した行数(カーディナリティ)です。
ここの予測が実際の件数と大きくズレていると、Oracleは間違った実行計画を選択してしまい、パフォーマンスが著しく劣化することがあります。例えば、本当は1件しか返らないのに、100万件返ってくると予測して、非効率な結合方法を選んでしまう、などです。
このズレが大きい場合は、テーブルの統計情報が古い可能性が高いです。DBMS_STATSパッケージを使って統計情報を更新することで、劇的に改善することがあります。
システムエンジニアとして実践したいこと
実行計画を読めるようになることは、ゴールではなくスタートです。世界一のシステムエンジニアを目指す私たちは、そこから「どうすればもっと良くなるのか?」を考え、行動に移さなければなりません。
- 仮説を立てる: 「この
TABLE ACCESS FULLは、column_aにインデックスを張ればINDEX SCANに変わるはずだ」 - 実行計画で検証する: 開発環境でインデックスを張り、
EXPLAIN PLANで実行計画が仮説通りに変わるか確認する。 - 効果を測定する:
AUTOTRACEを使って、Costの値や実際の実行時間がどれだけ改善したかを測定する。
この「仮説→検証→測定」のサイクルを回し続けることこそが、SQLチューニングの王道であり、エンジニアとしての実力を飛躍させる原動力になります。時にはOracleのHint句を使って、強制的に実行計画を制御するといった高度なテクニックも必要になるでしょう。
まとめ
いかがでしたでしょうか?
実行計画は、SQLのパフォーマンス問題を解決するための、最強の武器であり、DBとの対話ツールです。最初はとっつきにくく感じるかもしれませんが、今回ご紹介したポイントを押さえて何度も見ているうちに、必ず読めるようになります。
実行計画が読めるようになると、なぜこのSQLが遅いのかが論理的にわかり、的確な改善策を打てるようになります。それは、エンジニアとしてのあなたの市場価値を大きく高めることに繋がるはずです。
パフォーマンス問題を華麗に解決できる、市場価値の高いエンジニアを目指して頑張りましょう!


コメント