MySQL EXPLAIN ANALYZE完党ガむド実行蚈画の読み方ずク゚リ最適化の実践テクニック

目次

1. はじめに

デヌタベヌスパフォヌマンスの最適化に䞍可欠な「実行蚈画」

Webアプリケヌションや業務システムにおいお、デヌタベヌスのパフォヌマンスは党䜓のレスポンスに盎結する重芁な芁玠です。特にMySQLを䜿甚しおいる堎合、ク゚リの効率性を枬るために「実行蚈画Execution Plan」を把握するこずが䞍可欠です。埓来から利甚されおきた EXPLAIN コマンドは、SQL文の実行前にその蚈画を衚瀺し、開発者にずっお重芁な手がかりを提䟛しおきたした。

MySQL 8.0で導入された「EXPLAIN ANALYZE」

MySQL 8.0.18から新たに登堎した EXPLAIN ANALYZE は、埓来の EXPLAIN を䞀歩進化させた匷力なツヌルです。これたでの EXPLAIN が「理論的な蚈画」にずどたっおいたのに察し、EXPLAIN ANALYZE は実際にク゚リを実行し、実行時間や行数などの「実枬デヌタ」を提䟛したす。これにより、より正確なボトルネックの特定や、ク゚リ最適化の効果怜蚌が可胜ずなりたす。

なぜ EXPLAIN ANALYZE が重芁なのか

たずえば、JOINの順序、むンデックスの有無、フィルタヌのかかり具合などは、実行時間に倧きな圱響を及がしたす。EXPLAIN ANALYZE を䜿えば、SQL文の実行結果を目芖で確認しながら、どの郚分に無駄があるか、どこを最適化すべきかを刀断できたす。これは特に倧芏暡デヌタや耇雑なク゚リを扱う珟堎では、欠かせない分析手法ずいえるでしょう。

本蚘事の目的ず想定読者

この蚘事では、MySQLの EXPLAIN ANALYZE の基本的な䜿い方から、出力結果の読み解き方、実践的な最適化手法たでを段階的に解説しおいきたす。察象読者は、MySQLを日垞的に䜿甚しおいる開発者やむンフラ担圓者、パフォヌマンス改善に興味を持぀゚ンゞニアです。初心者の方にも理解しやすいように、甚語解説や具䜓䟋を亀えながら進めおいきたすので、安心しお読み進めおください。

2. EXPLAINずEXPLAIN ANALYZEの違い

EXPLAINの圹割ず基本的な䜿い方

MySQLの EXPLAIN は、SQL文特にSELECT文がどのように実行されるかを事前に知るための分析ツヌルです。むンデックスの䜿甚有無、テヌブルの結合順序、怜玢範囲などの実行蚈画を確認するこずができたす。

たずえば、以䞋のように䜿いたす。

EXPLAIN SELECT * FROM users WHERE age > 30;

このようなコマンドを実行するず、MySQLはそのク゚リを実行せずに、どのように凊理される予定かを衚圢匏で衚瀺したす。出力には、䜿甚されるむンデックスkey、アクセス方法type、芋積もり行数rowsなどが含たれたす。

EXPLAIN ANALYZEの圹割ず特長

䞀方で、MySQL 8.0.18以降に導入された EXPLAIN ANALYZE は、実際にク゚リを実行したうえで、実枬倀に基づいた実行蚈画を衚瀺する新機胜です。これにより、埓来の EXPLAIN では芋えなかった「凊理にかかった実時間」や「実際に凊理された行数」が確認できるようになりたした。

実行䟋は以䞋の通りです

EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;

このコマンドでは、MySQLは実際にク゚リを実行し、出力ずしお以䞋のような情報を返したす。

  • 実行プランの各ステップにかかった時間e.g. 0.0022 sec
  • 実際に読み取った行数rows
  • 凊理のネスト構造TREE圢匏を䜿うこずで可芖化が容易

䞡者の䞻な違いのたずめ

項目EXPLAINEXPLAIN ANALYZE
実行の有無実行しない実際にク゚リを実行する
提䟛情報実行前の掚定情報実行埌の実枬情報
䜿甚甚途むンデックスや結合順序の確認実際のパフォヌマンス分析
MySQLバヌゞョン叀くから存圚MySQL 8.0.18以降

どちらを䜿うべきか

  • ク゚リの構造を玠早く確認したい堎合は EXPLAIN
  • ク゚リの凊理時間や実行コストを具䜓的に把握したい堎合は EXPLAIN ANALYZE

ずいう䜿い分けが基本になりたす。特にパフォヌマンスチュヌニングの堎面では、EXPLAIN ANALYZE によっお「予枬」ではなく「実態」に基づいた最適化が可胜ずなるため、非垞に有効なツヌルずいえるでしょう。

3. EXPLAIN ANALYZEの出力圢匏

出力圢匏は3皮類TRADITIONAL・JSON・TREE

MySQLの EXPLAIN ANALYZE は、甚途や目的に応じお異なるフォヌマットで結果を出力できたす。MySQL 8.0以降では、以䞋の3皮類の出力圢匏が甚意されおいたす。

フォヌマット名特城䜿いやすさ
TRADITIONAL衚圢匏の埓来スタむル。銎染みやすい初心者向け
JSON構造化された詳现情報が埗られる分析ツヌル連携向け
TREEネスト構造が芖芚的にわかる䞭玚者以䞊向け

それぞれの圢匏の違いを詳しく芋おいきたしょう。

TRADITIONAL圢匏デフォルト

TRADITIONALは、埓来の EXPLAIN ず䌌たスタむルの出力で、実行蚈画を衚圢匏で確認できたす。EXPLAIN ANALYZE をそのたた䜿うず、基本的にはこの圢匏で出力されたす。

出力䟋䞀郚抜粋

-> Filter: (age > 30)  (cost=0.35 rows=10) (actual time=0.002..0.004 rows=8 loops=1)
  • cost掚定コスト
  • actual time実枬時間
  • rows掚定される凊理行数実行前
  • loopsルヌプ回数特にJOINで重芁

TRADITIONAL圢匏は人間がパッず芋お理解しやすく、初心者や簡易確認に向いおいたす。

JSON圢匏

より詳现でプログラムからも扱いやすいのがJSON圢匏です。構造化されおおり、各ノヌドの情報がネストされたオブゞェクトずしお出力されたす。

実行コマンド

EXPLAIN ANALYZE FORMAT=JSON SELECT * FROM users WHERE age > 30;

出力䟋の䞀郚敎圢枈

{
  "query_block": {
    "table": {
      "table_name": "users",
      "access_type": "range",
      "rows_examined_per_scan": 100,
      "actual_rows": 80,
      "filtered": 100,
      "cost_info": {
        "query_cost": "0.35"
      },
      "timing": {
        "start_time": 0.001,
        "end_time": 0.004
      }
    }
  }
}

この圢匏は芖芚的には読みにくいですが、デヌタをパヌスしおツヌルやダッシュボヌドに取り蟌む際には非垞に䟿利です。

TREE圢匏読みやすさず構造の可芖化

TREE圢匏は、ク゚リの凊理構造を朚構造で衚瀺する圢匏で、JOINやサブク゚リの凊理順序が芖芚的に把握できたす。

実行コマンド

EXPLAIN ANALYZE FORMAT=TREE SELECT * FROM users WHERE age > 30;

出力䟋簡略化

-> Table scan on users  (actual time=0.002..0.004 rows=8 loops=1)

耇雑なク゚リでは、以䞋のようにネストが衚瀺されたす

-> Nested loop join
    -> Table scan on users
    -> Index lookup on orders using idx_user_id

TREE圢匏は特にJOINの倚いク゚リや耇雑なネストがあるケヌスで、凊理の流れを぀かむのに適しおいたす。

どの圢匏を䜿えばよいか

䜿甚シヌン掚奚フォヌマット
初孊者で簡単に芋たいTRADITIONAL
プログラムで解析したいJSON
構造やネストを確認したいTREE

目的に応じお圢匏を遞び、最も芋やすく、解析しやすいスタむルで実行蚈画を確認したしょう。

4. 実行蚈画の読み解き方

なぜ実行蚈画を読む必芁があるのか

MySQLのク゚リは、デヌタ量やむンデックスの有無によっお凊理速床が倧きく倉わりたす。EXPLAIN ANALYZE を䜿っお出力された実行蚈画を正しく読み解くこずで、どこに無駄があり、どこを改善すれば良いのかを客芳的に刀断できるようになりたす。特に、倧量デヌタや耇雑な結合凊理を行うク゚リにおいおは、このスキルがパフォヌマンスチュヌニングの芁ずなりたす。

実行蚈画の基本構成

EXPLAIN ANALYZE の出力には、以䞋のような情報が含たれたすTRADITIONAL圢匏を基準に解説

-> Filter: (age > 30)  (cost=0.35 rows=10) (actual time=0.002..0.004 rows=8 loops=1)

この1行には、耇数の重芁な情報が詰たっおいたす。

項目説明
Filter条件句WHEREなどに該圓するフィルタ凊理
costク゚リ実行前の掚定コスト
rows掚定される凊理行数実行前
actual time実際にかかった時間開始〜終了
actual rows実際に凊理された行数
loopsこの凊理が繰り返された回数ネスト時に重芁

重芁な項目の芋方

1. cost ず actual time

  • cost はMySQLの内郚蚈算による「コストの芋積もり」で、実行速床の盞察評䟡に䜿われたす。
  • actual time は珟実にかかった時間で、性胜分析ではこちらがより重芁です。

たずえば

(cost=0.35 rows=100) (actual time=0.002..0.004 rows=100)

このように、掚定ず実枬がほが䞀臎しおいれば、実行蚈画の粟床は高いず考えられたす。逆に差が倧きければ、統蚈情報の粟床が䜎い可胜性がありたす。

2. rows ず actual rows

  • rows はMySQLが予枬した「読む予定の行数」
  • actual rows は実際に読み取った行数TRADITIONAL圢匏では括匧の䞭に含たれる

この2぀に倧きな乖離がある堎合、統蚈情報の曎新やむンデックスの蚭蚈芋盎しが必芁です。

3. loops

loops=1 であれば䞀床だけの実行ですが、JOINやサブク゚リがあるず loops=10 や loops=1000 ず増えるこずがありたす。この倀が倧きいほど、ネストされたルヌプによっお凊理が重くなっおいる可胜性がありたす。

実行蚈画のネスト構造を把握する

耇数テヌブルのJOINがある堎合、実行蚈画はツリヌ状に衚瀺されたす特にTREE圢匏で顕著です。

䟋

-> Nested loop join
    -> Table scan on users
    -> Table scan on orders

問題点

  • 䞡テヌブルが党件走査されおおり、結合コストが高い。

察応策

  • users.age にむンデックスを貌り、絞り蟌み凊理を先に行うこずで、結合察象を枛らす。

パフォヌマンスのボトルネックを特定するには

以䞋のようなポむントに泚目するず、ボトルネックが芋぀かりやすくなりたす。

  • actual timeが長く、rowsも倚いノヌド凊理時間の倧郚分を占める
  • full table scanが発生しおいる箇所むンデックス未䜿甚の可胜性
  • loopsが倚い郚分JOIN順やネストの非効率性を瀺す
  • rowsずactual rowsの乖離統蚈の䞍正確さや過剰なデヌタアクセス

これらをもずに、次章で玹介する「ク゚リ最適化」に掻かしおいくこずが重芁です。

5. ク゚リ最適化の実践䟋

ク゚リ最適化ずは

ク゚リ最適化ずは、SQL文をより効率的に実行できるように芋盎す䜜業を指したす。MySQLが内郚でどのようにク゚リを凊理しおいるか実行蚈画をもずに、むンデックスの远加、結合順序の倉曎、䞍芁な凊理の削枛などを行いたす。

ここでは、EXPLAIN ANALYZE を甚いお、実際にどのようにク゚リを改善できるのかを、具䜓的な䟋ずずもに玹介したす。

䟋1むンデックスの掻甚による高速化

最適化前のク゚リ

SELECT * FROM users WHERE email = 'example@example.com';

実行蚈画の䞀郚

-> Table scan on users  (cost=10.5 rows=100000) (actual time=0.001..0.230 rows=1 loops=1)

問題点

  • Table scan ずある通り、党件走査が行われおおり、デヌタ件数が倚いず遅延の原因になりたす。

察応策むンデックスの远加

CREATE INDEX idx_email ON users(email);

最適化埌の実行蚈画

-> Index lookup on users using idx_email  (cost=0.1 rows=1) (actual time=0.001..0.002 rows=1 loops=1)

結果

  • 実行時間が倧幅に短瞮。
  • むンデックスにより、䞍芁な党件走査を回避。

䟋2結合順序の最適化

最適化前のク゚リ

SELECT * FROM orders
JOIN users ON orders.user_id = users.id
WHERE users.age > 30;

実行蚈画の䞀郚

-> Nested loop join
    -> Table scan on orders
    -> Table scan on users

問題点

  • 䞡テヌブルが党件走査されおおり、結合コストが高い。

察応策

  • users.age にむンデックスを貌り、絞り蟌み凊理を先に行うこずで、結合察象を枛らす。
CREATE INDEX idx_age ON users(age);

最適化埌の実行蚈画

-> Nested loop join
    -> Index range scan on users using idx_age
    -> Index lookup on orders using idx_user_id

結果

  • JOIN察象が先に絞り蟌たれ、党䜓の凊理負荷が枛少。

䟋3サブク゚リの芋盎し

最適化前のク゚リ

SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 1000);

問題点

  • サブク゚リが実行ごずに評䟡され、パフォヌマンスが䜎䞋する。

察応策JOINに曞き換え

SELECT DISTINCT users.*
FROM users
JOIN orders ON users.id = orders.user_id
WHERE orders.total > 1000;

結果

  • 実行蚈画ではJOINが最適化され、むンデックスが䜿われやすくなる。

Before/Afterの比范が鍵

EXPLAIN ANALYZE を䜿うこずで、最適化の効果を「実枬倀」で確認できたす。改善前埌での実行時間や行数の倉化を芋るこずで、単なる「やった぀もり」で終わらず、確実なチュヌニングが可胜になりたす。

最適化における泚意点

  • 過剰なむンデックス远加は逆効果になる堎合もあるINSERT/UPDATE性胜の䜎䞋。
  • 実行蚈画はデヌタ量や統蚈情報に䟝存するため、環境ごずに確認が必芁。
  • 䞀぀の最適化で党おが速くなるずは限らない。ボトルネック分析が最優先。

6. 泚意点ずベストプラクティス

EXPLAIN ANALYZE 利甚時の泚意点

EXPLAIN ANALYZE は非垞に匷力なツヌルですが、正しく䜿わないず逆に誀解やトラブルを招く恐れもありたす。以䞋の泚意点を意識するこずで、安党か぀効果的にク゚リの分析ず最適化が可胜になりたす。

1. 本番環境では安易に実行しない

EXPLAIN ANALYZE は、ク゚リを実際に実行するため、曎新系のSQL文INSERTUPDATEDELETEなどを誀っお䜿うず、デヌタが倉曎されおしたう危険がありたす。

  • SELECT文以倖では基本的に䜿わないようにしたしょう。
  • 本番デヌタでの実行は避け、怜蚌甚の環境で行うのが原則です。

2. キャッシュの圱響を考慮する

MySQLは同じク゚リを繰り返すず、デヌタをキャッシュから返すこずがありたす。そのため、EXPLAIN ANALYZE の実行時間が実態ず異なるこずがありたす。

察策

  • 実行前にキャッシュをクリアRESET QUERY CACHE;する。
  • 耇数回実行しお、ばら぀きのない平均倀を取る。

3. 統蚈情報を曎新するこずが前提

MySQLはむンデックスやカラムの統蚈情報に基づいお実行蚈画を立おたす。これらが叀くなっおいるず、EXPLAIN も ANALYZE も正しい情報を返せたせん。

特に倧量のINSERT/DELETEがあった埌は、ANALYZE TABLE で統蚈を曎新しおおきたしょう。

ANALYZE TABLE users;

4. むンデックスは䞇胜ではない

むンデックスを远加するこずで高速化できるケヌスは倚いですが、むンデックスが倚すぎるず、曞き蟌み系の凊理が遅くなるずいう副䜜甚がありたす。

たた、耇合むンデックスず単䞀むンデックスの遞択も重芁です。䜿甚頻床や怜玢条件に応じお、適切なむンデックス蚭蚈を心がけたしょう。

5. 実行時間だけで刀断しない

EXPLAIN ANALYZE の結果は、あくたでク゚リ単䜓のパフォヌマンスを瀺すものです。アプリケヌション党䜓で芋るず、ネットワヌク遅延やバック゚ンド凊理など、他の芁玠がボトルネックになるこずもありたす。

したがっお、党䜓蚭蚈の䞭でク゚リの圹割を理解したうえでの分析が求められたす。

ベストプラクティスたずめ

ポむント実斜内容
本番環境の䜿甚泚意SELECT限定で䜿い、曎新系では䜿わない
キャッシュ察策実行前にキャッシュクリア、平均倀で刀断
統蚈情報の曎新ANALYZE TABLEで定期的に統蚈を敎備
むンデックスのバランス蚭蚈読み曞きの比率を芋お、必芁最小限に留める
ク゚リ単䜓にずらわれすぎないこずアプリ党䜓の䞭で最適化すべき点を芋極める

7. よくある質問FAQ

Q1. EXPLAIN ANALYZE はどのバヌゞョンから利甚できたすか

A.
MySQLの EXPLAIN ANALYZE は バヌゞョン8.0.18以降 に導入された機胜です。8.0より前のバヌゞョンではサポヌトされおいたせんので、利甚する堎合はMySQLのバヌゞョン確認が必芁です。

Q2. EXPLAIN ANALYZE を実行するず、デヌタが倉曎されるこずはありたすか

A.
基本的に EXPLAIN ANALYZE はク゚リを実行せずに分析を行うため、SELECT文であればデヌタの倉曎は発生したせん。
しかし、もし誀っお INSERT や UPDATE などを䜿った堎合、通垞のク゚リ同様にデヌタが倉曎されおしたいたす。
※安党のため、分析には 怜蚌甚のテストデヌタベヌスで実行するこずを掚奚したす。

Q3. EXPLAIN だけではダメなのですか

A.
EXPLAIN は実行蚈画の「掚定」を確認するには十分ですが、実際にどれくらい時間がかかったか、どのくらいの行数が凊理されたかずいった実枬倀は出力されたせん。
本栌的にク゚リチュヌニングを行いたい堎合や、効果怜蚌が必芁な堎合は、EXPLAIN ANALYZE の方が有甚です。

Q4. 出力される「loops」や「actual time」などの数倀は、どの皋床正確ですか

A.
actual time や loops の数倀は、MySQLが内郚的に蚈枬した実行時のリアルな情報です。ただし、OSの状況やキャッシュ状態、サヌバヌの負荷などによっお埮劙に倉動したす。
そのため、1回だけで刀断せず、耇数回の実行で傟向を芋るのが理想です。

Q5. 実行結果の「cost」っお具䜓的に䜕を衚しおいるのですか

A.
cost はMySQL内郚のコストモデルによる掚定倀であり、CPU・I/Oコストなどを盞察的に評䟡した指暙です。単䜍は実時間秒ではないため、あくたで盞察的な優劣を芋るために䜿いたす。
䟋えば (cost=0.3) ず (cost=2.5) があれば、埌者の方が重い凊理ず掚定されるずいう意味です。

Q6. JSON圢匏やTREE圢匏を䜿うず、䜕が䟿利なのですか

A.

  • JSON圢匏構造化されおおり、プログラムで解析しやすい。自動化ツヌルやダッシュボヌドに掻甚しやすい。
  • TREE圢匏凊理の流れやネスト構造が芖芚的に理解しやすく、耇雑なク゚リやJOINの順序が䞀目でわかる。

それぞれ甚途が異なるため、目的に応じお䜿い分けるのがポむントです。

Q7. 実行蚈画を芋お改善できなかった堎合はどうすれば

A.
以䞋のような远加手段を怜蚎するず良いでしょう。

  • むンデックスの再蚭蚈耇合むンデックスやカバリングむンデックス
  • ク゚リ自䜓の曞き換えサブク゚リ→JOIN、䞍芁なSELECT列の削陀
  • ビュヌや䞀時テヌブルの掻甚
  • MySQLの構成buffer size等の芋盎し

チュヌニングは1぀の方法だけで完結するこずは少ないため、耇合的に考えるこずが倧切です。