コース一覧
データベース内部構造:インデックス・トランザクション・分散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

インデックスチューニング

貼ったのに、速くならない

遅い一覧画面を見つけ、WHERE に出てくる列に索引を追加した。デプロイして測り直したら、ほとんど変わっていない。よくある話です。

まず確かめるのは、貼った索引が使われているかどうかです。EXPLAIN の key 欄に自分が作った索引名が出ているか、PostgreSQL なら Index Scan になっているか。名前が出ていないなら速くならないのは当然で、直すべきは索引ではなく条件の書き方の側です。

索引が効かなくなる書き方

索引に並んでいるのは、列の値そのものです。ですから、条件がその値から離れるほど使えなくなります。

SQL クエリ

WHERE LOWER(email) = 'alice@example.com'
WHERE YEAR(created_at) = 2026
WHERE user_id = '100'          -- user_id は整数の列

最初の 2 つは、列を関数で包んでいます。索引にあるのは包む前の値なので突き合わせられません。3 つ目は型が違うため、DB が内部で変換を挟み、結果として関数で包んだのと同じことになります。日付は範囲条件へ書き換え、文字と数値は呼び出し側で型を揃えれば、どちらも解消します。

SQL クエリ

WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01'

前方一致でない LIKE も同じ理由で効きません。'山田%' は先頭が決まっているので並び順から探せますが、'%山田%' は先頭が分からないので全部見るしかありません。中間一致が業務要件なら、索引の張り方を工夫するのではなく、全文検索の仕組みを別に用意します。

もう 1 つ、書き方ではなくデータの偏りが原因の場合があります。退会済みフラグのように値が 2 種類しかない列に索引を貼っても、半分の行が該当するなら、索引をたどってから本体を引くより全部読んだ方が速い。プランナが索引を無視するのはこの場合で、判断としては正しい動きです。絞り込みに効くのは、該当する行が全体の数パーセント以下に収まる条件だと考えてください。

複数列に貼るときは、順番で結果が変わる

(user_id, created_at) の索引は、user_id で並べ、同じ user_id の中を created_at で並べたものです。順番を入れ替えれば別物になります。

条件効き方
user_id = ?効く
user_id = ? AND created_at > ?両方効く
created_at > ? だけ効かない

先頭の列が条件に出てこないと、その索引には出番がありません。並べる順は、等号で絞る列を先に、範囲で絞る列や並べ替えに使う列を後に置きます。範囲条件から後ろの列は、並び順の恩恵を受けられないためです。

「ある利用者の注文を新しい順に 20 件」という画面なら、絞り込みに使う user_id が先、並べ替えに使う created_at が後です。この順なら、該当する利用者のかたまりの中がすでに日付順に並んでいるので、端から 20 件取れば終わります。逆順に作ると、日付順に並んだ全体の中から user_id の一致する行を拾い直すことになり、20 件そろえるまでに関係のない行を大量に読みます。

なお索引は書き込みのたびに更新されます。使われていない索引は、遅くする効果しかありません。

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

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

  • デプロイ本番環境へアプリを配置し公開する作業
  • PostgreSQL機能が豊富なオープンソースのRDBMS
  • 関数処理に名前を付けて再利用できる単位
  • 判断YES/NO 分岐を表す菱形
生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/27·更新 2026/08/26

関連レッスン

  • 統計情報とカーディナリティ

    プランナがコストを計算するために使う統計の仕組み

  • レプリケーション

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

  • Nested Loop / Hash / Merge Join

    3 種類の結合アルゴリズムと最適な場面を比較する

  • EXPLAIN の読み方

    MySQL / PostgreSQL の実行計画出力を実例で読み解く

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

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