コース一覧
データベース内部構造:インデックス・トランザクション・分散DB
カバリングインデックス

データベース内部構造:インデックス・トランザクション・分散DB

SQLの書き方ではなく、DBMSの内側を学ぶコースです。RDBとNoSQL、正規化、B-tree、トランザクションとMVCC、クエリプランナ、レプリケーションと分散SQLを通して、性能と整合性の判断根拠を身につけます。

1
データベースの基礎
0. データベースとは8分
1. RDB と NoSQL の違い8分
2. データベースの歴史8分
3. エンティティ関係モデル (ER)8分
4. 主キー・外部キー・候補キー8分
2
正規化
0. 正規化とは何か8分
1. 第1正規形8分
2. 第2正規形8分
3. 第3正規形8分
4. 非正規化のトレードオフ8分
3
インデックスと B-tree
0. インデックスの役割8分
1. B-tree の仕組み8分
2. B+tree(実際の DB 実装)8分
3. ハッシュインデックス8分
4. カバリングインデックス8分
4
トランザクションと ACID
0. トランザクションとは8分
1. ACID 特性8分
2. 分離レベル8分
3. MVCC(マルチバージョン同時実行制御)8分
4. デッドロックと回避8分
5
クエリ最適化
0. クエリプランナの役割8分
1. EXPLAIN の読み方8分
2. Nested Loop / Hash / Merge Join8分
3. インデックスチューニング8分
4. 統計情報とカーディナリティ8分
6
スケーリング
0. レプリケーション8分
1. シャーディング8分
2. CAP 定理8分
3. 結果整合性8分
4. NewSQL と分散 SQL8分

データベース内部構造:インデックス・トランザクション・分散DB

01データベースとは
02RDB と NoSQL の違い
03データベースの歴史
04エンティティ関係モデル (ER)
05主キー・外部キー・候補キー
06正規化とは何か
07第1正規形
08第2正規形
09第3正規形
10非正規化のトレードオフ
11インデックスの役割
12B-tree の仕組み
13B+tree(実際の DB 実装)
14ハッシュインデックス
15カバリングインデックス
16トランザクションとは
17ACID 特性
18分離レベル
19MVCC(マルチバージョン同時実行制御)
20デッドロックと回避
21クエリプランナの役割
22EXPLAIN の読み方
23Nested Loop / Hash / Merge Join
24インデックスチューニング
25統計情報とカーディナリティ
26レプリケーション
27シャーディング
28CAP 定理
29結果整合性
30NewSQL と分散 SQL

データベース内部構造:インデックス・トランザクション・分散DB

カバリングインデックス

索引に当たっているのに、まだ遅い

一覧画面が遅いので実行計画を見たら、索引はちゃんと使われていました。全件走査でもありません。それでも 3 秒かかります。

原因は、索引を引いたあとにあります。検索用の索引の葉に入っているのは主キーの値までで、画面に出したい氏名や金額は入っていません。だから DB は、索引が返した主キーを 1 件ずつ持って、本体の側をもう一度引きに行きます。この往復は 1 件につき 1 回です。該当が 1 万件なら 1 万回です。

1 件だけ返すクエリなら誤差ですが、まとめて返すクエリでは、この往復が支配的になります。索引が効いているのに遅いときは、たいていここです。

実行計画に索引の名前が出ていることは、速いことの証明にはなりません。索引でどこまで絞れたか、そのあと本体を何回引いたかまで見て、初めて遅さの原因が分かります。

欲しい列を、索引の中に入れてしまう

往復が起きるのは、欲しいものが索引の中に無いからです。ならば入れてしまえばよい、というのがカバリングインデックスです。

そのクエリが必要とする列を全部含んだ索引にしておくと、索引を読んだ時点で答えが揃います。本体を引きに行く必要がなくなり、往復はゼロになります。

SQL クエリ

CREATE INDEX idx_orders_user_created
  ON orders (user_id, created_at, status, total);

この並び順には理由があります。前から順に、等号で絞る列、並べ替えに使う列、最後に取り出したいだけの列、という順番です。先頭が絞り込みに効き、途中が並べ替えの手間を省き、後ろが往復を消します。取り出すだけの列を前に置くと、絞り込みも並べ替えも効かなくなります。

MySQL の InnoDB では、どの索引の葉にも主キーの値が必ず入っています。だから主キーだけを取り出すクエリは、何もしなくても最初からこの状態です。PostgreSQL には、取り出す専用の列を並び順に加えずに索引へ含める書き方があり、索引を太らせずに同じ効果を得られます。

全部入れれば速い、ではない

では欲しい列を片っ端から入れればよいかというと、そうはいきません。

含めた列は、そのまま索引の大きさになります。長い説明文の列を 1 つ入れるだけで、索引が本体と同じくらい重くなることがあります。重い索引はメモリを占め、他の索引を追い出します。

書き込みにも跳ね返ります。含めた列のどれか 1 つが更新されるたびに、この索引も直します。取り出したいだけで入れた列が、更新の多い列だった場合、往復を消して得た分を書き込みで払い直すことになります。

新しく作る前に、すでにある索引を見ます。同じ列から始まる索引がすでにあるなら、そこへ列を足すほうが安く済みます。似た索引を 2 本並べると、読むときはどちらか一方しか使われないのに、書き込みでは両方が更新されます。

そこで、含めるのは短くて更新の少ない列に絞ります。判断の目安は、そのクエリが 1 回に何件返すかです。数件しか返さないなら往復も数回なので、索引を太らせる価値はありません。数千件を返す一覧や、集計のために大量に読む処理でだけ効きます。件数が増えるほど効き方も大きくなるので、いま遅いところだけでなく、これから件数が伸びる場所を先に見ておくと無駄が出ません。狙いどおり効いているかは、実行計画に「索引だけで完結した」旨が出るかどうかで確かめられます。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • 外部キーテーブル同士を結びつける鍵
  • 主キーレコードを一意に特定する列
  • インデックスDB 検索を速くする索引
  • MySQL広く使われるオープンソースのRDBMS
  • PostgreSQL機能が豊富なオープンソースのRDBMS
  • メモリプログラムとデータを一時保持する高速領域
  • 判断YES/NO 分岐を表す菱形
  • 処理計算や代入を表す長方形
生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/27·更新 2026/08/26

関連レッスン

  • トランザクションとは

    BEGIN / COMMIT / ROLLBACK の意味と必要性を学ぶ

  • クエリプランナの役割

    SQL から実行計画が生成される過程を追う

  • レプリケーション

    Primary / Replica 構成での読み取り分散と整合性

分からないところは Tap (AI先生) に質問できます

24 時間いつでも、あなたのレベルに合わせて日本語で答えます。