永続化 ACIDと正規化
概要
- 日程: Day 3 / セッション 5
- 時間: [13:00-13:30]
- 形式: 座学
- ゴール: ACID特性の4要素を列挙して一言ずつ説明できる(行動・基準)。家計簿システムを例に(条件)、RDBの正規化とKey-Valueストアの使い分け、およびインピーダンス・ミスマッチとO/Rマッピングの関係を説明できる(行動・基準)
- 学習形式: 対話型解説
導入(5分)
午前中は「どう設計するか」という思想の話でした。午後は一気に地面に降ります。テーマは永続化です。
ここで少し考えてみてください。
あなたが作った家計簿システムで、ペルソナの佐藤さんが30分かけて今月の支出を入力し終えた瞬間、ブラウザが落ちたとします。
再起動したら入力は全部消えていました。佐藤さんはこのアプリを二度と開かないでしょう。
プログラムの変数はメモリ上にあり、電源が切れれば消えます。
データを電源断やプログラム終了の後も残すこと、これが永続化(persistence)です。
ただし「ファイルに書けば終わり」ではありません。
書き込みの途中で落ちたら? 2人が同時に書いたら? ここで登場するのがACIDです。
そしてRDBに保存するとき、あなたのデータは「正規化」という変形を受けます。
このセッションの最後に、本日いちばん大事な対比を予告します。
情報モデルはペルソナのため、正規化はコンピュータのため。この一文を頭に置いて聞いてください。
本編(20分)
1. 永続化とACID トランザクションの4つの約束
データの保存で怖いのは「中途半端」です。
定番のたとえは銀行振込です。振込とは、次の2つの処理の組です。
- 処理1: Aさんの口座から1万円を引く
- 処理2: Bさんの口座に1万円を足す
処理1の直後にサーバが落ちたらどうなるでしょうか。1万円がこの世から消えます。
これを防ぐため、データベースは複数の処理をトランザクションという1つの束にまとめ、ACIDという4つの約束を守ります。
- A: Atomicity(原子性): 束の中の処理は「全部成功」か「全部なかったこと」のどちらかにする。半分だけは無い
- C: Consistency(一貫性): トランザクションの前後で、データは決めたルール(制約)を満たし続ける。「口座残高は0以上」等が破れた状態で確定しない
- I: Isolation(独立性・分離性): 同時に走るトランザクション同士は互いに干渉しない。1つずつ順に実行したのと同じ結果になる
- D: Durability(永続性): 「成功した」と返答した結果は、直後に電源が落ちても消えない
原子性と一貫性は混同しやすいので対比しておきます。
「処理1だけ実行された状態」を防ぐのは原子性に該当しますが、一貫性には該当しません。
なぜなら一貫性が守るのは「実行の全部か無か」ではなく「ルール(残高0以上等)が破れていないか」だからです。
コード例・実例
家計簿システムで「今月の予算から5,000円ぶんを『食費』カテゴリに振り替える」トランザクションをSQLで書くとこうなります。
BEGIN; -- トランザクション開始
UPDATE budgets SET amount = amount - 5000 WHERE category = '未割当';
UPDATE budgets SET amount = amount + 5000 WHERE category = '食費';
COMMIT; -- 2つまとめて確定
-- 途中で不整合に気づいたら
ROLLBACK; -- 全部なかったことにする
COMMITが成功して初めて、2つのUPDATEは世界に存在し始めます(原子性・永続性)。
途中でエラーが出ればROLLBACKで開始前に戻ります。
ここがポイント
- ACID=原子性・一貫性・独立性・永続性。まず4つを言えること
- 原子性は「全部か無か」、一貫性は「ルールが破れないこと」。守るものが違う
- BEGIN/COMMIT/ROLLBACKがトランザクションの基本操作。明日の実装でも意識する
コラム
ACIDは狙って作られた語呂合わせ
ACIDという頭字語は、1983年にテオ・ヘルダーとアンドレアス・ロイターが論文「Principles of Transaction-Oriented Database Recovery」で定義しました。概念自体はジム・グレイらの先行研究にありましたが、2人はそれをAtomicity・Consistency・Isolation・Durabilityの4語に整えて「ACID(酸)」と読める並びにしました。英語には「acid test(真価を問う厳しい試験)」という慣用句があり、金の純度を酸で確かめた故事に由来します。「データベースの真価を問う4条件」に酸の名を与えたのは、狙い澄ました命名です。名前付け(Day 2のモデリング4要素の1つ)が概念の普及を決めた好例で、後にBASEという「塩基」を名乗る対抗概念まで生まれました。
2. 永続化の方法 ファイル・RDB(正規化)・Key-Valueストア
永続化の手段は1つではありません。代表は3つです。
- ファイル: JSONやCSVをそのまま書く。手軽だが、同時書き込みや部分更新に弱い。設定ファイルや1人用の小さなデータ向き
- RDB(リレーショナルデータベース): 表の集まりで保存する。ACIDを守り、正規化で重複を排除する。業務データの本命
- Key-Valueストア: キーと値の対だけで保存する。構造が単純なぶん高速・分散向き。セッション情報やキャッシュ向き
「高機能なRDBが常に正解」ではありません。
「ログイン中ユーザの一時セッション」はKey-Valueストアが該当しますが、「家計簿の支出記録」は該当しません。
なぜならセッションは「キーで1件取れれば十分・消えても再ログインで済む」データですが、支出記録は「集計・検索され、絶対に消えてはいけない」データだからです。
さて、RDBの核心が正規化です。正規化とは、表を分解して重複と矛盾の芽を取り除く手続きです。
家計簿の支出を、正規化せずに1枚の表に書くとこうなります。
| 日付 | 金額 | カテゴリ名 | カテゴリ説明 | ユーザ名 |
|---|---|---|---|---|
| 7/1 | 800 | 食費 | 食事・食材の支出 | 佐藤 |
| 7/1 | 500 | 食費 | 食事・食材の支出 | 佐藤 |
| 7/2 | 1200 | 交際費 | 飲み会・プレゼント | 佐藤 |
「食費」の説明文が2回書かれています。もし「食費」の説明を直すなら全行を直す必要があり、1行でも直し忘れると矛盾が生まれます。これを更新不整合と呼びます。
正規化は段階を踏みます。家計簿の例で一気に見ます。
- 第1正規形: 1マスに1つの値だけにする(「カテゴリ: 食費、外食」のような複数値を許さない)
- 第2正規形: 主キーの一部だけで決まる項目を別の表に出す
- 第3正規形: 主キー以外の項目から決まる項目を別の表に出す(カテゴリ名が決まれば説明文が決まる→categories表へ)
分解の結果はこうなります。
(日付・金額・カテゴリ名・カテゴリ説明・ユーザ名が全行に重複)"] Raw -->|正規化(第1〜第3正規形)| E["expenses
(id, 日付, 金額, category_id, user_id)"] Raw -->|カテゴリの重複を分離| C["categories
(id, カテゴリ名, 説明)"] Raw -->|ユーザの重複を分離| U["users
(id, ユーザ名)"] E -->|category_id で参照| C E -->|user_id で参照| U
事実が1か所にだけ書かれる状態になりました。「食費」の説明を直す場所は、世界に1行だけです。
コード例・実例
正規化後のテーブルをSQLで定義すると、ACIDの「一貫性」を守る制約も書けます。
CREATE TABLE categories (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE -- カテゴリ名の重複を禁止
);
CREATE TABLE expenses (
id INTEGER PRIMARY KEY,
spent_on DATE NOT NULL, -- 日付は必須
amount INTEGER NOT NULL CHECK (amount >= 0), -- 金額は0以上
category_id INTEGER NOT NULL REFERENCES categories(id) -- 実在カテゴリのみ
);
Day 2で情報モデルに書いた制約条件(「金額は0以上」「日付は必須」)が、そのままCHECKやNOT NULLになっています。情報モデルは実装への橋渡し役だ、という話の実物です。
ここがポイント
- 永続化はファイル・RDB・Key-Valueストアの使い分け。データの性質(消えてよいか・集計するか)で選ぶ
- 正規化の目的は「事実を1か所にだけ書く」こと。重複が消えれば更新不整合が消える
- 第1〜第3正規形の細かい定義の暗記より、「重複を見つけたら表を分ける」という動きを覚える
コラム
コッド博士と、上司に無視された論文
正規化と関係モデルの生みの親は、IBMの数学者エドガー・F・コッドです。1970年の論文「A Relational Model of Data for Large Shared Data Banks」で、データを数学の「関係(表)」として扱う理論を発表しました。ところが当時のIBMは階層型データベースIMSの大黒柱を抱えており、自社製品を否定しかねないコッドの理論に冷淡でした。この論文に飛びついたのが外部の人々で、その一人ラリー・エリソンは1977年に会社を興し、IBMより先に商用RDBを出荷します。後のOracleです。IBMが本気を出したときには市場を追う側でした。「正しい理論は、発表した組織の都合を待ってくれない」という、情報産業でくり返し起きる物語の代表例です。
3. インピーダンス・ミスマッチとO/Rマッピング
最後に、明日の実装で必ず出会うズレの話をします。
プログラム(JavaScript等)の世界では、データはオブジェクトです。入れ子になり、ひとかたまりで扱えます。
RDBの世界では、データは正規化された複数の表です。平らで、分かれています。
この2つの世界の構造のズレをインピーダンス・ミスマッチと呼びます。
電気回路で抵抗(インピーダンス)が合わない機器をつなぐと信号がうまく伝わらないことに由来する比喩です。
プラグの形が違う海外旅行のようなものです。電気は来ているのに、変換アダプタなしでは繋がりません。
そのアダプタが**O/Rマッピング(Object-Relational Mapping、ORM)**です。
オブジェクトと表の間の詰め替え作業を、規則を決めて自動化する仕組みです。
「構造のズレ」がインピーダンス・ミスマッチに該当しますが、「SQLの書き間違いによるエラー」は該当しません。
なぜならミスマッチはバグではなく、両方の世界がそれぞれ正しいのに形が合わないという構造的な問題だからです。
コード例・実例
同じ「支出1件」が、2つの世界でどう見えるかを並べます。
// プログラムの世界: 1つのオブジェクト(入れ子・ひとかたまり)
const expense = {
spentOn: "2026-07-01",
amount: 800,
category: { name: "食費", description: "食事・食材の支出" },
user: { name: "佐藤" }
};
RDBの世界: 3つの表に分かれた3行
expenses: (id=1, spent_on=2026-07-01, amount=800, category_id=10, user_id=5)
categories: (id=10, name=食費, description=食事・食材の支出)
users: (id=5, name=佐藤)
1個のオブジェクト=3表3行。この詰め替えを毎回手で書くのは苦行なので、ORMライブラリ(Prisma、Sequelize等)が肩代わりします。
ここがポイント
- インピーダンス・ミスマッチは「オブジェクトの世界」と「表の世界」の構造のズレ。どちらかが間違いなのではない
- O/Rマッピングはそのズレを埋める変換アダプタ
- ズレが存在すること自体が、次のセッションのテーマ「同じ情報が視点によって別の姿になる」の証拠
コラム
「ORMはコンピュータサイエンスのベトナム」
2006年、技術者テッド・ニューワードはO/Rマッピングを「コンピュータサイエンスのベトナム(泥沼)」と評したエッセイを発表し、大論争を巻き起こしました。最初は簡単に見えて、深入りするほど撤退も勝利もできなくなる、という比喩です。オブジェクトの継承を表でどう表すか、どこまで一括で読み込むか。ORMの奥には今も決定版のない設計判断が潜んでいます。とはいえ現代の実務ではORMは標準装備です。大切なのは「ORMを使えばズレが消える」ではなく「ズレは残るが、詰め替えの手間を減らせる」と正しく期待することです。銀の弾丸ではなく、良くできた変換アダプタです。
💬 AIに聞いてみよう
聞き慣れない用語が残っていたら、このまま次の演習に入る前にAIに質問してみましょう。
- 「ACIDの『一貫性』と『独立性』の違いを、家計簿アプリを2人が同時に使う場面を例に説明してください」
- 「家計簿システムのデータのうち、RDBではなくKey-Valueストアに置くべきものはありますか。理由も教えてください」
- 「第2正規形と第3正規形の違いを、家計簿の表を1つ例に作って、分解の前後を見せながら説明してください」
まとめ(5分)
今回学んだことを一言でまとめると「永続化はACIDで安全に保存し、RDBでは正規化で重複を排除する。そのとき生じるオブジェクトとのズレを埋めるのがO/Rマッピング」です。
- ACID=原子性・一貫性・独立性・永続性。トランザクションの4つの約束
- 永続化の手段はファイル・RDB・Key-Valueストア。データの性質で使い分ける
- 正規化は「事実を1か所に」。第1〜第3正規形で表を分解する
- オブジェクトと表の構造のズレ=インピーダンス・ミスマッチ。埋めるのがORM
ここで冒頭の予告を回収します。
Day 2で作った情報モデルは、ペルソナが価値を見出す形をしていました。
今日見た正規化済みテーブルは、コンピュータが矛盾なく管理できる形をしています。
同じ「支出」なのに、姿が違う。情報モデルはペルソナのため、正規化はコンピュータのためです。
次のセッション6では、あなた自身の情報モデルを実際に正規化して、この違いを自分の目で確かめます。
🔄 振り返りチェック
- ACIDの4要素を、何も見ずに列挙して一言ずつ説明できますか?
- 「家計簿の支出記録はRDB、セッション情報はKey-Valueストア」という使い分けの理由を言えますか?
- インピーダンス・ミスマッチが「バグではない」理由を、オブジェクトと表という言葉を使って説明できますか?
補足資料
- 参考リンク:
- E. F. Codd「A Relational Model of Data for Large Shared Data Banks」(1970, CACM)
- SQLite公式ドキュメント(トランザクション): https://www.sqlite.org/lang_transaction.html
- IPA 基本情報技術者試験シラバス(データベース分野): https://www.ipa.go.jp/
- 発展課題:
- 銀行振込の例をBEGIN/UPDATE×2/COMMITのSQLで書き、「処理1の直後にサーバが落ちた場合」に何が起きるかをAIと確認してみましょう
- BASE特性(ACIDの対抗概念)を調べ、「家計簿システムに採用してよいか」を自分の非機能要件一覧書と照らして判断してみましょう
学習ガイド
想定される質問と回答例
| 質問 | ヒント |
|---|---|
| 一貫性と独立性の違いが曖昧 | 一貫性は「ルール(残高0以上等)が破れないこと」、独立性は「同時実行が干渉しないこと」。1人で使っても一貫性は問題になるが、独立性は複数同時のときだけ問題になる、と切り分ける |
| 第2正規形と第3正規形の違いを覚えられない | 「主キーの一部で決まるか(第2)/主キー以外で決まるか(第3)」。暗記より「決まり方の矢印を探して、その先を別表に出す」動きで覚える。分からなければAIに例を作らせる |
| ファイル保存ではなぜだめなのか | だめではなく用途が違う。1人用・少量・同時書き込みなしならファイルで十分。同時アクセス・部分更新・障害復旧が要るならACIDを備えたRDBが要る |
| ORMを使えばSQLは覚えなくてよい? | ORMは詰め替えの自動化であり、裏では必ずSQLが発行されている。性能問題や不具合の調査ではSQLを読む場面が必ず来るので、基本のSQLは読めるようにしておく |
つまずきやすいポイント
| つまずきポイント | ヒント |
|---|---|
| ACIDの4語は言えるが、原子性と一貫性の説明が同じになってしまう | 原子性は「全部か無か」という実行のされ方、一貫性は「制約が破れていないか」という状態のルール。銀行振込で「片方だけ実行」は原子性違反、「残高がマイナスのまま確定」は一貫性違反、と例で区別する |
| 正規形の定義(第1〜第3)を暗記しようとして手が止まる | このセッションでの合格ラインは「重複を見つけたら表を分ける」という動きの説明。厳密な定義は演習で必要になったときにAIに確認すればよい |
| 「正規化すれば常に正しい」と考え、ファイルやKey-Valueストアの出番を忘れる | 正規化はRDBの中の技法にすぎない。永続化の選択肢は3つあり、データの性質(消えてよいか・集計するか・同時に書くか)で選ぶのが先 |
| インピーダンス・ミスマッチを「設計ミスやバグ」だと誤解する | オブジェクトも表も、それぞれの世界では正しい形。ズレは構造的なもので、消すのではなくORMで橋を架けて付き合う |