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

デッドロックと回避

お互いが、相手の持っているものを待っている

2 つの処理が、口座間の振替をほぼ同時に始めたとします。

プレーンテキスト

T1: UPDATE accounts SET balance = balance - 100 WHERE id = 1;  -- 行 1 を確保
T2: UPDATE accounts SET balance = balance - 200 WHERE id = 2;  -- 行 2 を確保
T1: UPDATE accounts SET balance = balance + 100 WHERE id = 2;  -- 行 2 が空くのを待つ
T2: UPDATE accounts SET balance = balance + 200 WHERE id = 1;  -- 行 1 が空くのを待つ

T1 が待っている行 2 は T2 が握っていて、T2 が待っている行 1 は T1 が握っています。どちらも相手が手放すのを待っているので、放っておけば永遠に進みません。これがデッドロックです。

タイムアウトまで待つ必要はありません。DBMS は「誰が誰を待っているか」を追っていて、待ちの関係が一周して輪になったことを見つけると、片方を選んで強制的に巻き戻します。巻き戻された側のアプリには、こういうエラーが返ります。

プレーンテキスト

ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction

輪ができるのは、順番が食い違ったときだけ

上の例で、T1 は 1 番、2 番の順に触り、T2 は 2 番、1 番の順に触っています。もし両方が「番号の小さい行から触る」と決めていたら、後から来た方は最初の行で待たされ、先の 1 本が終わるまで次の行を握ることはありません。輪は作れません。

ですから対策は、ロックの種類を覚えることでも設定を変えることでもなく、まずこの順番を揃えることです。複数行をまとめて押さえるなら ORDER BY id を付けて取る。テーブルをまたぐなら「注文、そのあと明細」のように触る順をコードの規約として決める。全経路で順番が同じなら、待ちは一列に並びます。

握っている時間を短くするのも同じ方向の話です。外部 API の応答待ちをトランザクションの内側に入れると、その数百ミリ秒のあいだ相手を待たせ続け、輪ができる隙が広がります。

起きる前提で、やり直せるようにしておく

順番を揃えても、ゼロにはなりません。同じ行への集中や、想定と違う実行計画で押さえる範囲が広がることもあります。デッドロックは設計ミスの証拠ではなく、たまに起きるものとして扱い、アプリ側で自動的にやり直します。

JavaScript

async function withRetry(operation, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await operation();
    } catch (err) {
      if (err.code !== "ER_LOCK_DEADLOCK" || i === maxRetries - 1) throw err;
      await sleep(Math.random() * 100 * (i + 1));
    }
  }
}

待ち時間に乱数を混ぜているのは、巻き戻された 2 本が同時にやり直して、また同じ形でぶつかるのを避けるためです。回数の上限は必ず決めます。無限にやり直すと、原因の調査ができないまま負荷だけが増えていきます。

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

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

  • 処理計算や代入を表す長方形
  • デッドロック複数トランザクションが互いの解放を待ち、永遠に止まる状態
  • ロック「他の人触らないでね」と DB に予約する
  • テーブルDB の表 (Excel のシートみたいなもの)
  • エンドポイント「この URL を叩くとこの機能が動く」入口の住所
  • APIアプリ間でデータをやり取りする窓口
  • トランザクション「全部成功 or 全部なかったことに」をまとめる単位
  • 設計何をどう作るかを決める前工程
生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/27·更新 2026/08/26

関連レッスン

  • クエリプランナの役割

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

  • レプリケーション

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

  • MVCC(マルチバージョン同時実行制御)

    読み手をブロックしないバージョン管理の仕組み

  • 分離レベル

    Read Uncommitted から Serializable まで 4 段階を比較する

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

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