MySQLインデックス入門!データベースの速度を劇的に変える仕組みと基本を徹底解説
生徒
「データベースからデータを取り出すのが遅い気がするんです。どうにか速くする方法はありませんか?」
先生
「そんなときは『インデックス』という魔法の目次を使うのが一般的ですよ。これを使えば、膨大なデータの中から一瞬で目的の情報を見つけ出せます。」
生徒
「目次ですか?本についているようなアレのことですか?」
先生
「まさにその通りです。今回は、パソコンの操作に自信がない方でもわかるように、インデックスの仕組みを詳しく解説していきますね。」
1. インデックスとは何か?(辞書の目次の仕組み)
MySQL(マイエスキューエル)というデータベースを操作していると、データが増えるにつれて「検索」に時間がかかるようになります。これを解決するのがインデックス(Index)です。
想像してみてください。あなたは今、一万ページもある巨大な辞書の中から「林檎(りんご)」という言葉を探しています。もし目次がなかったら、どうしますか?おそらく最初の1ページ目から順番に、「あ」から始まる言葉をずっとめくって探さなければなりません。これを「フルスキャン(全件走査)」と呼びます。データが少ないうちはこれでも間に合いますが、データが数百万件、数千万件になると、パソコンでも非常に時間がかかってしまいます。
そこで登場するのがインデックスです。辞書の索引(さくいん)のように、「『ら』行の言葉は〇〇ページにある」という情報をまとめた別表をデータベースの中に作っておくのです。これにより、データベースは全てのデータを見ることなく、最短ルートで目的のデータにたどり着くことができるようになります。これが、データベースのパフォーマンスを最適化するための第一歩です。
2. インデックスがない状態での検索(フルスキャン)
まずは、インデックスが設定されていないテーブルで検索を行うとどうなるかを見てみましょう。ここでは、会員制サイトのユーザー情報を管理する「users(ユーザーズ)」というテーブルを例にします。
id | name | age | email | city
---+-----------+-----+----------------------+---------
1 | 山田太郎 | 25 | taro@example.com | 東京
2 | 佐藤花子 | 19 | hanako@example.com | 大阪
3 | 鈴木一郎 | 30 | ichiro@example.com | 名古屋
4 | 田中次郎 | 22 | jiro@example.com | 福岡
5 | 伊藤純子 | 28 | junko@example.com | 札幌
6 | 渡辺健 | 35 | ken@example.com | 横浜
7 | 中村美紀 | 24 | miki@example.com | 仙台
8 | 小林大介 | 31 | daisuke@example.com | 広島
このテーブルから、特定のメールアドレスを持つ人を探すSQL文を書いてみます。
SELECT *
FROM users
WHERE email = 'miki@example.com';
実行結果は以下のようになります。
id | name | age | email | city
---+-----------+-----+----------------------+---------
7 | 中村美紀 | 24 | miki@example.com | 仙台
インデックスがない場合、コンピュータは上から順番に「1番目のメールアドレスはこれか?違う」「2番目は?違う」と1件ずつチェックしていきます。この例では7番目で見つかりましたが、もし100万番目に目的のデータがあったら、それまで100万回の確認作業を行う必要があるのです。これが「検索が遅い」原因となります。
3. インデックスを作成して検索を高速化する
次に、メールアドレスの列にインデックスを作成してみましょう。インデックスを作成するには CREATE INDEX という命令を使います。これは、メールアドレスのリストを五十音順(あるいはアルファベット順)に並べ替えた「専用の道案内板」をデータベースの裏側に作るイメージです。
CREATE INDEX idx_email ON users(email);
この命令を実行した後は、データベースの動きが劇的に変わります。先ほどと同じ検索命令を投げると、データベースは「あ、メールアドレスの目次があるな」と気づき、目次を使って瞬時に場所を特定します。まるで分厚い本を一瞬で開き、お目当てのページを指差すようなスピード感です。これがインデックスの最大のメリットです。
4. インデックスの仕組み(B-Tree構造)
少し専門的なお話をすると、MySQLのインデックスの多くは「B-Tree(ビーツリー)」という構造で管理されています。これは「木」を逆さまにしたような形をしています。一番上に「根(ルート)」があり、そこから枝分かれして、最後に「葉(リーフ)」にたどり着きます。
例えば、数字の1から100までの中から「85」を探すとき、B-Treeを使えば「50より大きいか小さいか?」「75より大きいか小さいか?」という風に、二択を繰り返すだけであっという間に正解にたどり着けます。これを「木構造の探索」と呼びます。プログラミングの経験がなくても、トーナメント表をイメージすれば分かりやすいかもしれません。優勝チーム(目的のデータ)を特定するために、一試合ずつ絞り込んでいくようなものです。
この仕組みがあるおかげで、たとえデータが1億件あったとしても、わずか数十回の計算だけで目的の1件を見つけ出すことができるのです。これがMySQLの驚異的なパフォーマンスを支えている技術です。
5. インデックスを貼る際の注意点とデメリット
ここまで聞くと「全部の列にインデックスを貼ればいいじゃないか」と思うかもしれませんが、実はデメリットもあります。インデックスは「魔法の杖」ではありません。以下の3つのポイントに注意しましょう。
① 書き込みが遅くなる
インデックスは「本に目次を書き足す作業」です。新しいデータが追加(INSERT)されたり、データが書き換え(UPDATE)られたりするたびに、データベースは目次も一緒に書き直さなければなりません。目次が多すぎると、データを1件入れるたびに10個も20個も目次を修正することになり、逆に追加作業が重くなってしまいます。
② 保存容量(ストレージ)を消費する
インデックスは元のデータとは別に保存されるものです。つまり、目次を作れば作るほど、ハードディスクの容量をたくさん使います。スマートフォンの写真が増えると容量がいっぱいになるのと同じで、無駄なインデックスは控えなければなりません。
③ カーディナリティ(選択性)を考える
「カーディナリティ」という難しい言葉が出てきましたが、これは「データの種類の多さ」のことです。例えば「性別(男性・女性)」のような、種類が少ない列にインデックスを貼ってもあまり意味がありません。目次を開いても「男性は1ページ目から500ページ目までです」と書かれているだけで、結局たくさん探さなければならないからです。逆に「メールアドレス」や「社員番号」のように、一人ひとり違う値が入っている列は、インデックスの効果が非常に高いです。
6. 複合インデックスによる高度な最適化
実際の業務では、「名前」と「年齢」を組み合わせて検索することもあります。そのような場合には「複合インデックス」という、複数の列をセットにした目次を作ることができます。
id | name | age | email | city
---+-----------+-----+----------------------+---------
1 | 山田太郎 | 25 | taro@example.com | 東京
2 | 佐藤花子 | 19 | hanako@example.com | 大阪
3 | 鈴木一郎 | 30 | ichiro@example.com | 名古屋
4 | 田中次郎 | 22 | jiro@example.com | 福岡
5 | 伊藤純子 | 28 | junko@example.com | 札幌
6 | 渡辺健 | 35 | ken@example.com | 横浜
7 | 中村美紀 | 24 | miki@example.com | 仙台
8 | 小林大介 | 31 | daisuke@example.com | 広島
例えば、「25歳以上の山田さん」を探すためのインデックスを作ってみましょう。
CREATE INDEX idx_name_age ON users(name, age);
このインデックスを使うと、データベースはまず「名前」で絞り込み、その中でさらに「年齢」で絞り込むという、より精度の高い検索が可能になります。これは、住所録で「東京都」→「千代田区」→「永田町」と順番に絞り込んでいくのと同じ仕組みです。このように、よく一緒に使われる条件をセットにすることで、データベースの速度をさらに向上させることができます。
7. 実行計画(EXPLAIN)でインデックスの確認
最後に、本当にインデックスが使われているかを確認する方法をご紹介します。MySQLには「EXPLAIN(エクスプレイン)」という、命令の裏側を覗き見るツールがあります。使い方は簡単で、いつものSQL文の前に EXPLAIN と付けるだけです。
EXPLAIN SELECT * FROM users WHERE email = 'miki@example.com';
これを使うと、データベースが「今回はどの目次を使ったか」「何件のデータを調べたか」を教えてくれます。プログラミングに慣れてくると、この結果を見て「あ、インデックスが効いていないから遅いんだな」と判断して、修正を行えるようになります。
データベースの世界は奥が深いですが、まずは「インデックス=検索を速くするための目次」という基本をしっかり押さえておけば、効率の良いシステムを作ることができるようになります。データの整理整頓が得意なデータベースは、私たちが情報を扱う上でとても心強い味方になってくれるはずです。