インデックスとトランザクション
概要
- 日程: Day 2 / セッション 11
- 時間: 15:40-16:00
- 形式: 座学
- ゴール: インデックスを「索引」のたとえで説明し、ACID 特性と BEGIN/COMMIT/ROLLBACK の流れを説明できる
- 学習形式: 対話型解説
導入(5分)
これまでで「読む・書く・つなぐ・設計する」をひと通り学びました。最後の座学では、業務でデータベースを使うときに必ず知っておきたい2大トピックを扱います。
ひとつは「インデックス」——たくさんあるデータから目的の1行を素早く見つける仕組み。もうひとつは「トランザクション」——複数の操作を「ひとまとまりの仕事」として安全に処理する仕組み。
このセッションは20分の短時間ですが、業務で「これを知らないと困る」最頻出の話題です。
本編(15分)
1. インデックスは「本の索引」
たとえば1万ページの分厚い辞書から「postgres」という単語を探したいとき、皆さんはどうしますか?最初のページから順に読みますか?普通は巻末の索引(インデックス)を見て、「postgres → 8,432ページ」と当たりをつけてから本文を開きますよね。
データベースのインデックスもまったく同じ発想です。テーブル全体を端から読む(フルスキャン)代わりに、別途用意した索引を使って目的の行に直接アクセスする仕組みです。
コード例・実例
インデックスの作成はシンプルです。
CREATE INDEX idx_employees_email ON employees(email);
「employeesテーブルのemail列に索引を作る」という意味です。これで WHERE email = 'xxx@example.com' の検索が劇的に速くなります。
sandbox には既にいくつかインデックスが用意されています。
\di
idx_employees_department、idx_orders_customer などが見えるはずです。これらは「JOINで頻繁に使われる外部キー列」に対して張られています。
ここがポイント
- 主キー列とUNIQUE列には自動でインデックスが張られる
- 検索が速くなるが、INSERT/UPDATE/DELETE は少し遅くなる(索引の更新が必要なため)
- 全列に張ればよいわけではない。「よく検索する列」「JOINに使う列」が候補
コラム
インデックスは万能薬ではありません。実例として、ある会社で「とにかく全列にインデックスを張れば速くなる」と信じた新人エンジニアが、20列のテーブルの全列に索引を作った結果、INSERTがそれまでの10倍遅くなり、夜間バッチが朝までに終わらなくなった、という事件があったそうです。索引は「読みやすくなる代わりに書くのが重くなる」というシーソーです。本の索引も、本を作る人にとっては余計な作業ですよね。あれと同じです。
2. トランザクション=「ひとまとまりの仕事」
銀行の振込を考えてみてください。AさんからBさんへ1万円送るとき、データベース上では次の2つの操作が必要です。
- Aさんの残高から1万円減らす
- Bさんの残高に1万円増やす
もし1だけ実行された瞬間に停電したら?1万円が消えてしまいます。逆に2だけ実行されたら、お金が湧いて出ます。どちらも困るので、「両方とも成功するか、両方とも無かったことにするか」のどちらかにしたい——これがトランザクションの発想です。
コード例・実例
PostgreSQL では、こう書きます。
BEGIN;
UPDATE accounts SET balance = balance - 10000 WHERE id = 'A';
UPDATE accounts SET balance = balance + 10000 WHERE id = 'B';
COMMIT; -- 両方とも確定
途中で間違いに気付いたら:
BEGIN;
UPDATE accounts SET balance = balance - 10000 WHERE id = 'A';
-- あ、Bさんじゃなくて Cさんだった!
ROLLBACK; -- なかったことにする
ROLLBACK するとBEGIN以降の変更が全て元に戻ります。「UPDATE を打つ前に BEGIN する」という習慣は、命綱です。
ここがポイント
BEGINで開始、COMMITで確定、ROLLBACKで取り消し- COMMIT前なら、別のセッションからは変更前の値が見える
- DELETEやUPDATEを試したいときは、まず
BEGINで守ってから打つと安心
3. ACID特性:トランザクションの4つのお約束
トランザクションが信頼できる仕組みである理由は、DBMSが「ACID」と呼ばれる4つの性質を守ってくれるからです。
| 頭文字 | 名前 | ひと言で |
|---|---|---|
| A | Atomicity(原子性) | 全部やるか、全部やらないか |
| C | Consistency(一貫性) | ルール(制約)を破った状態にはならない |
| I | Isolation(独立性) | 他のトランザクションから干渉されない |
| D | Durability(永続性) | COMMITしたデータは停電しても消えない |
ここがポイント
- 振込の例で全部説明できる:両方成功か両方失敗(A)、残高がマイナスにならない(C)、他の取引と混ざらない(I)、COMMIT後は停電しても残る(D)
- 試験でよく聞かれる定番。「ACIDって何の頭文字?」は必ず覚える
💬 AIに聞いてみよう
- 「インデックスはどんな列に張るべきで、どんな列には張らない方がいい?」
- 「
BEGINを打ったままCOMMITもROLLBACKもせずに放置したらどうなる?」 - 「ACID のうち、現実のDBで一番守るのが難しいのはどれ?」
まとめ(5分)
インデックスは「本の索引」のたとえで覚えれば一発。検索は速くなるが、書き込みは少し遅くなるトレードオフ。CREATE INDEX 名前 ON テーブル(列); で作れます。
トランザクションは「ひとまとまりの仕事」。BEGIN → 一連の操作 → COMMIT または ROLLBACK。ACID(原子性・一貫性・独立性・永続性)の4つを DBMS が守ってくれます。
次は確認テストです。Day1から学んだ全範囲を15問で振り返ります。緊張する必要はありません、現時点の自分の理解度を把握するための「健康診断」と思って臨んでください。
🔄 振り返りチェック
- インデックスのメリットとデメリットを1つずつ言えますか?
- BEGIN/COMMIT/ROLLBACK の役割を、振込の例で説明できますか?
- ACIDの4つの頭文字と意味を全部言えますか?
補足資料
- 参考リンク: PostgreSQL公式 - インデックス / トランザクション
- 発展課題:
EXPLAIN SELECT ... WHERE email = 'xxx';を、インデックスがある場合とない場合で比べてみる(実行計画の読み方をAIに教わる)
学習ガイド
想定される質問と回答例
| 質問 | ヒント |
|---|---|
| インデックスは何種類もあるの? | B-tree(標準)、Hash、GIN、GiSTなど。普通の用途ではB-treeで十分 |
| インデックスを作ったのに速くならない | データ量が少ない、検索条件が「先頭部分一致」ではない、統計情報が古い、などの原因がある |
COMMIT を忘れたまま接続を切ったら? |
自動的に ROLLBACK される(多くのDBの既定動作)。書きかけは全部破棄 |
autocommit って何? |
1文ごとに自動でCOMMITするモード。psql のデフォルトはこれ。明示的にBEGINを打つとオフになる |
つまずきやすいポイント
| つまずきポイント | ヒント |
|---|---|
| インデックスを張れば全部速くなると思う | 「読みのコスト ↓、書きのコスト ↑」のトレードオフ。万能ではない |
BEGIN を忘れて DELETE を打って事故る |
UPDATE/DELETEは必ず BEGIN から、結果を確認してから COMMIT する習慣を |
| ACID をただ暗記する | 「振込の例」と紐付けて理解する。試験以外でも応用が利く |