MySQLのEXPLAIN徹底解説!type列の意味を初心者向けに図解・例えで分かりやすく紹介
生徒
「データベースの動きが遅いとき、EXPLAIN(エクスプレイン)という命令を使うと良いって聞いたんですけど、中身を見ても英語ばかりで意味が分かりません……。」
先生
「確かに、最初は暗号のように見えますよね。EXPLAINは、いわば『データベースの健康診断書』です。特に『type』という項目を見ると、データを探すときに『効率よく探しているか』『力任せに探しているか』が分かりますよ。」
生徒
「健康診断書ですか!パソコンの操作に慣れていない私でも、どこをチェックすればいいか分かりますか?」
先生
「もちろんです。今回は、図書館で本を探すような身近な例えを使って、一番重要な『type列』の見方をゆっくり解説していきますね。」
1. SQLとEXPLAINの基本を知ろう
SQL(エスキューエル)は、データベースという「情報の保管庫」に対して、「このデータを持ってきて!」とお願いするための専用の言葉です。例えば、お店の会員名簿から「東京に住んでいる人だけ教えて」と頼むときに使います。
しかし、データが何万件、何十万件と増えてくると、探し出すのに時間がかかるようになります。そこで登場するのがEXPLAIN(エクスプレイン)です。EXPLAINは、日本語で「説明する」という意味です。SQL文の先頭に「EXPLAIN」と付けて実行するだけで、データベースがどのようにデータを探しに行くつもりなのか、その計画書(実行計画)を表示してくれます。
この計画書を読むことで、プログラミング初心者の方でも「なぜ検索が遅いのか」という原因を突き止めることができるようになります。
2. EXPLAINの「type」列はなぜ重要?
EXPLAINを実行すると、たくさんの項目が表示されますが、初心者がまず見るべきなのは「type」という列です。これは「データの探し方の種類」を表しています。
データを探す方法は、大きく分けて2つあります。1つは「最初から最後まで全部見る」方法。もう1つは「目次(インデックス)を使ってパッと見つける」方法です。type列には、この探し方の効率の良さが英語のキーワードで表示されます。
この値を見ることで、あなたの書いたSQLが「賢い探し方」をしているのか、それとも「力ずくの非効率な探し方」をしているのかが一目で判断できるのです。検索エンジンの最適化(SEO)と同じように、データベースも無駄な動きを減らすことが、高速なウェブサイトを作る秘訣となります。
3. 一番最悪な「ALL」:全件スキャンの恐怖
type列に「ALL」と表示されたら、それは要注意のサインです。これは「フルテーブルスキャン」と呼ばれ、テーブルにある全てのデータを一行ずつ順番にチェックしている状態を指します。
例えば、100万ページある辞書の中から、目次を一切使わずに1ページ目から最後までめくって言葉を探しているようなものです。データが数件なら一瞬で終わりますが、データが増えれば増えるほど、どんどん時間がかかるようになります。
実際の例を見てみましょう。会員名簿テーブル「users」を用意しました。
id | name | city | age
---+----------+---------+-----
1 | 佐藤太郎 | 東京都 | 25
2 | 鈴木花子 | 大阪府 | 32
3 | 高橋一郎 | 福岡県 | 28
4 | 田中愛子 | 北海道 | 45
5 | 伊藤健二 | 東京都 | 20
ここで、「東京都」に住んでいる人を検索するSQLを実行し、その計画を確認します。
EXPLAIN SELECT * FROM users WHERE city = '東京都';
もし「city」という項目に目次(インデックス)が設定されていない場合、結果は以下のようになります。
id | select_type | table | type | key | rows
---+-------------+-------+------+------+-----
1 | SIMPLE | users | ALL | NULL | 5
「type」が「ALL」になっていますね。これは、東京都の人を探すために、5人全員をチェックしたことを意味します。これが100万人だったら、100万人全員を調べることになり、パソコンが悲鳴を上げてしまいます。
4. 少しマシな「index」:目次を全部見る
次に紹介するのは「index」です。「目次(インデックス)があるなら速いんじゃないの?」と思うかもしれませんが、実はこの「index」もあまり効率が良くありません。
これは「目次(インデックス)を、端から端まで全部読み込む」という状態です。本の本文を全部読むよりはマシですが、目次のページを最初から最後まで全部読んでいるので、結局手間がかかっています。
例えば、名前順に並んでいる名簿の「目次」だけを見て、特定の条件に合う人を数えるような場合です。全てのデータを見る(ALL)よりはデータ量が少ない分だけ速いですが、根本的な解決にはなっていません。
5. かなり優秀な「range」:範囲を決めて探す
「range」と表示されたら、少し安心してください。これは「範囲検索」と呼ばれ、目次を使って「ここからここまで」とアタリをつけて探している状態です。
例えば、「年齢が20歳から30歳までの人」を探すときに、目次を使って20歳のページへ一気に飛び、そこから30歳のところまでだけを確認する方法です。最初から最後まで見る必要がないため、スピードが大幅にアップします。
先ほどのテーブルで、年齢(age)に目次(インデックス)を付けた状態で検索してみましょう。
id | name | city | age
---+----------+---------+-----
1 | 佐藤太郎 | 東京都 | 25
2 | 鈴木花子 | 大阪府 | 32
3 | 高橋一郎 | 福岡県 | 28
4 | 田中愛子 | 北海道 | 45
5 | 伊藤健二 | 東京都 | 20
EXPLAIN SELECT * FROM users WHERE age BETWEEN 20 AND 30;
実行結果のイメージはこちらです。
id | select_type | table | type | key | rows
---+-------------+-------+-------+-----+-----
1 | SIMPLE | users | range | age | 3
「type」が「range」になり、実際に調べた行数(rows)も少なくなっています。このように「必要な範囲だけ」を見るのが、データベース操作のコツです。
6. 理想的な「ref」:特定の値をズバリ見つける
「ref」は、非常に効率が良い探し方です。「参照(reference)」の略で、ある特定のキーワードを指定して、それと同じデータを目次からパッと見つけてくる状態です。
例えば、国語辞典で「りんご」という単語を引くとき、目次を使って「ら行」のページを開き、すぐに「りんご」を見つけるような感覚です。特定の条件で一つ、あるいは数個のデータを抜き出すときにこの「ref」が表示されます。ここまで来れば、データベースの動作が重いと感じることはほとんどありません。
先ほどの「city(住所)」にインデックスを貼った状態で、再度検索をしてみます。
EXPLAIN SELECT * FROM users WHERE city = '東京都';
id | select_type | table | type | key | rows
---+-------------+-------+------+------+-----
1 | SIMPLE | users | ref | city | 2
先ほどは「ALL」だった検索が、「ref」に変わりました!これで、東京都の人だけを迷わず見つけられるようになったのです。
7. 最高速度の「const」:世界に一つだけを探す
最後に、最も速いのが「const(コンスト)」です。これは「定数」という意味で、探しているデータが「世界に一つしかない」ことが保証されている場合に出現します。
例えば、会員ID(id)は、一人ひとりに違う番号が割り振られていますよね。これを「主キー(プライマリキー)」と呼びます。このIDを指定して検索すると、データベースは「あ、これなら1個見つけたら終わりだ」と即座に判断できます。これが最強の検索スピードです。
id | name | city | age
---+----------+---------+-----
1 | 佐藤太郎 | 東京都 | 25
2 | 鈴木花子 | 大阪府 | 32
3 | 高橋一郎 | 福岡県 | 28
4 | 田中愛子 | 北海道 | 45
5 | 伊藤健二 | 東京都 | 20
EXPLAIN SELECT * FROM users WHERE id = 3;
id | select_type | table | type | key | rows
---+-------------+-------+-------+---------+-----
1 | SIMPLE | users | const | PRIMARY | 1
「type」が「const」になっています。rows(調べた行数)も「1」です。一瞬で目的地にたどり着く、ワープのような速さです。
8. 初心者が覚えるべき改善のステップ
ここまでの内容をまとめると、type列の良し悪しは以下の順番になります。
const(最強) > ref > range > index > ALL(最悪)
もし、あなたが作ったシステムが遅いと感じたら、まずはEXPLAINを使って「ALL」や「index」が出ていないか確認しましょう。もし出ていたら、検索の条件に使っている項目(例えば「名前」や「日付」など)にインデックス(目次)を作成することを検討してください。
インデックスを作るということは、データベースの中に「整理された索引ページ」を作るということです。これだけで、数秒かかっていた検索が、0.01秒で終わるようになることも珍しくありません。パソコン操作に慣れていない方でも、この「type列のキーワード」をチェックするだけで、エンジニアのような分析ができるようになるのです。
9. 専門用語を分かりやすく解説
記事の中で出てきた難しい用語を整理しておきますね。
- データベース(DB):大量の情報を整理して、後から使いやすく保存しておくためのコンピュータ上の倉庫です。
- テーブル:データベースの中にある「表」のことです。Excelのシートのようなものをイメージしてください。
- レコード(行):表の中の「一行分」のデータです。一人分の会員情報などがこれにあたります。
- インデックス:本の最後にある「索引」や「目次」と同じ役割をします。これがあるおかげで、全部を読み飛ばして目的のページへ行けます。
- スキャン:データを読み取って調べることです。「全件スキャン」は端から端まで全部見ることを意味します。
- 主キー(プライマリキー):そのデータが世界に一つであることを証明する番号(IDなど)のことです。
これらの用語が分かると、プログラミングやデータベースの解説記事がもっと楽しく読めるようになりますよ。
まとめ
ここまで、MySQLのパフォーマンス改善に欠かせない「EXPLAIN」の実行計画、特に「type」列の意味について詳しく解説してきました。データベースの操作において、私たちが何気なく発行しているSELECT文が裏側でどのように動いているかを知ることは、プログラミングスキルを一段階引き上げるために非常に重要です。
データベースの高速化とSEOの共通点
ウェブサイトの運営においてSEO(検索エンジン最適化)が重要なように、データベースの世界でも「最適化」がパフォーマンスの鍵を握ります。Googleの検索エンジンがユーザーに最適なページを素早く届けるためにインデックス(索引)を活用するのと同様に、MySQLもインデックスを利用して膨大なレコードの中から目的のデータを瞬時に見つけ出します。
もし「type」列が「ALL」になっている場合、それは検索エンジンがサイトの全ページをインデックスなしで這いずり回っているような非効率な状態です。これではユーザーを待たせてしまい、結果としてUX(ユーザー体験)の低下を招きます。EXPLAINを活用して「const」や「ref」を目指すことは、まさにデータベースにおけるSEO対策と言えるでしょう。
現場で使える改善のチェックポイント
実際の開発現場や個人アプリの制作で、動作が重いと感じたときは以下の手順で確認を行ってみてください。
- WHERE句の確認:検索条件に使っているカラムにインデックスが貼られているか?
- 結合(JOIN)の確認:複数のテーブルを繋げるとき、結合キーにインデックスがあるか?
- データ量の想定:現在は数件でも、将来的に数万件に増えたときに「ALL」のままで耐えられるか?
実践!インデックス作成のサンプルプログラム
解説記事の中で、インデックスを貼ることで「ALL」が「ref」に変わることを学びました。では、実際にどのようにインデックスを作成するのか、SQLのコマンドを確認しておきましょう。
-- usersテーブルのcityカラムにインデックスを作成する
CREATE INDEX idx_city ON users(city);
-- インデックスが作成されたか確認する
SHOW INDEX FROM users;
-- 再びEXPLAINで、typeがALLから改善されたかチェックする
EXPLAIN SELECT * FROM users WHERE city = '東京都';
このように、インデックスを適切に設定することで、データベースは「力任せの全件スキャン」から卒業し、「賢い探索」へと進化します。特に「type」列が「range」や「ref」に変わった瞬間は、エンジニアとして非常に達成感を感じるポイントです。
今回学んだtype列の重要度ランク
最後におさらいとして、type列の評価を一覧表にまとめました。この表をブックマークしたり、メモしておくだけでも、いざという時のデバッグに役立ちます。
| 評価 | typeの値 | 状態の解説 |
|---|---|---|
| 要注意 | ALL | フルテーブルスキャン。全データを調べる最遅の状態。 |
| 改善推奨 | index | インデックスフルスキャン。ALLよりはマシだが効率は悪い。 |
| 良好 | range | インデックスを用いた範囲検索。一定の範囲のみを調べる。 |
| 優秀 | ref / eq_ref | インデックスを使って特定の値を検索。非常に高速。 |
| 理想 | const / system | 主キーなどによる一意の検索。これ以上ない最速の状態。 |
生徒
「先生、ありがとうございました!EXPLAINって難しいイメージがありましたけど、type列を見て『ALLを避ける』って考えるだけで、なんだか自分でも改善できそうな気がしてきました!」
先生
「その意気です!プロのエンジニアも、まずはそこからスタートします。特にデータが増えてきたときに、インデックス一つでアプリの速度が劇的に変わるのを体験すると、データベースの面白さがもっと分かりますよ。」
生徒
「さっそく自分の作っているプログラムでも『EXPLAIN』を付けて実行してみます。もし『ALL』が出ていたら、教えてもらった『CREATE INDEX』を試してみますね!」
先生
「素晴らしいですね。もしインデックスを貼っても速度が変わらない場合は、また別の『Extra』列という項目を見る必要があるのですが、それはまた次のステップで教えます。まずはこの『type』をマスターして、健康なデータベース設計を目指しましょう!」
生徒
「はい!まずは健康診断の結果(type)をしっかり読めるようになります!」