第8章 マスターデータとトランザクションデータ — 性質に応じて設計を変える
この章で学ぶこと
- マスターデータとトランザクションデータの違いを自分の言葉で説明できる
- それぞれのデータ性質に応じて適切な設計判断 (履歴管理 / パーティション / 削除戦略) ができる
- EC サイトや業務システムでどのテーブルがどちらに該当するかを見分けられる
第 7 章 基本用語と命名規則 を理解していること。
データには 2 つの性質がある
データベースに格納されるデータは、性質によって大きく 2 種類に分けられます。
この区別は、テーブル設計だけでなく、運用・バックアップ・性能チューニング・アーカイブ戦略まで、設計の至る所に影響します。
マスターデータとは — システムの「辞書」
マスターデータは、システムを動かすために基準となる情報です。商品マスタ・顧客マスタ・部署マスタなどの「マスタ」と呼ばれるテーブルがこれに該当します。
商品マスタの例
CREATE TABLE products (
id SERIAL PRIMARY KEY,
code VARCHAR(20) UNIQUE NOT NULL, -- 業務上の商品コード
name VARCHAR(200) NOT NULL,
category_id INTEGER NOT NULL REFERENCES categories(id),
unit_price NUMERIC(10, 2) NOT NULL,
tax_rate NUMERIC(4, 2) NOT NULL DEFAULT 10.0,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO products (code, name, category_id, unit_price) VALUES
('PROD-001', 'ノートパソコン', 1, 89800),
('PROD-002', 'マウス', 2, 2980),
('PROD-003', 'キーボード', 2, 4980);
商品マスタは「どの商品にどんな価格を設定しているか」を示す基準情報で、日々の注文処理がこれを参照します。
トランザクションデータとは — 日々の「履歴」
トランザクションデータは、業務活動の中で日々発生するデータです。注文・売上・入出庫・アクセスログなどが該当します。
注文データの例
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
order_number VARCHAR(20) UNIQUE NOT NULL,
customer_id INTEGER NOT NULL REFERENCES customers(id),
order_date TIMESTAMPTZ NOT NULL,
total_amount NUMERIC(12, 2) NOT NULL,
tax_amount NUMERIC(10, 2) NOT NULL,
status VARCHAR(20) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE order_items (
order_id BIGINT NOT NULL REFERENCES orders(id),
line_number INTEGER NOT NULL,
product_id INTEGER NOT NULL REFERENCES products(id),
quantity INTEGER NOT NULL,
unit_price NUMERIC(10, 2) NOT NULL, -- 注文時の価格をスナップショット
amount NUMERIC(12, 2) NOT NULL,
PRIMARY KEY (order_id, line_number)
);
unit_price を持つ理由商品マスタの unit_price を参照すれば済むようにも見えますが、注文時の価格を注文明細に「スナップショット」として保存するのが鉄則です。理由は、商品マスタの価格は将来変わる可能性があり、過去の注文を後から見たときに「当時いくらだったか」が正しく分かる必要があるからです。
マスターとトランザクションの関係
トランザクションデータは、必ずマスターデータを参照する形になります。
- 注文 (
orders) は顧客マスタ (customers) を参照する - 注文明細 (
order_items) は商品マスタ (products) を参照する - 商品 (
products) はカテゴリマスタ (categories) を参照する
トランザクションは「いつ・誰が・何を・どれだけ」の事実記録で、マスタは「誰 / 何」の基準情報、と整理できます。
マスター vs トランザクション — 特徴比較
| 観点 | マスターデータ | トランザクションデータ |
|---|---|---|
| 更新頻度 | 低 (月数回〜年数回) | 高 (秒単位で発生) |
| データ量 | 少 (数千〜数万件) | 多 (数百万〜数億件) |
| データ寿命 | 長 (年単位、ものによっては半永久) | 短〜中 (法定保存期間後にアーカイブ) |
| 業務上の重要度 | 極めて高い (壊れると全業務停止) | 高い (履歴の正確性が金銭価値に直結) |
| バックアップ戦略 | 全件保持・履歴も保持 | 期間で区切ってアーカイブ |
EC サイトでの具体例
設計時の考慮点
マスターデータ: 履歴管理が必要なケース
「商品の価格が変わったとき、過去の注文を遡って計算するために『当時の価格』を知りたい」というニーズがあります。これは前述のとおり注文明細に価格をスナップショットで持つのが基本ですが、商品の値上げ履歴自体を見たい場合は、マスター側にも履歴テーブルを設ける方法があります。
CREATE TABLE product_price_history (
id BIGSERIAL PRIMARY KEY,
product_id INTEGER NOT NULL REFERENCES products(id),
unit_price NUMERIC(10, 2) NOT NULL,
valid_from DATE NOT NULL,
valid_to DATE, -- NULL = 現在も有効
changed_by INTEGER NOT NULL REFERENCES users(id),
changed_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_pph_product ON product_price_history(product_id);
CREATE INDEX idx_pph_valid_period ON product_price_history(valid_from, valid_to);
valid_from / valid_to で「いつからいつまでこの価格だったか」を表現する設計です。これは「履歴データ」「期間モデル」「時系列モデル」などとも呼ばれます。
トランザクションデータ: 増え続けるデータへの対処
トランザクションデータは増え続けるため、何も対策しないと数年でテーブルが数億件に膨らみます。対策としては:
| 対策 | 内容 |
|---|---|
| アーカイブ | 古いデータを別テーブル / 別ストレージに移して本番テーブルを軽く保つ |
| パーティション | 1 つのテーブルを「日 / 月 / 年」単位の論理パーティションに分割し、検索を高速化 |
| 集計テーブル | 日次 / 月次の集計結果を別テーブルに事前計算しておき、レポート時の負荷を下げる |
| 適切なインデックス | 検索に使うカラムにインデックスを作る、使われないインデックスは削除 |
CREATE TABLE orders (
id BIGSERIAL,
order_date DATE NOT NULL,
customer_id INTEGER NOT NULL,
total_amount NUMERIC(12, 2) NOT NULL,
PRIMARY KEY (order_date, id)
) PARTITION BY RANGE (order_date);
CREATE TABLE orders_2025 PARTITION OF orders
FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');
CREATE TABLE orders_2026 PARTITION OF orders
FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');
パーティションは「テーブルが数億件以上に膨らんでから」考えるもので、最初から導入すると複雑さだけ増えます。Jr が新規プロジェクトで使うべき場面は限定的です。「困ってから入れる」スタンスで構いません。
データのライフサイクル
マスターデータは「不要になったら無効化して残す (is_active = false)」のが安全です。理由は、過去のトランザクションがそのマスターを参照していて、物理削除すると外部キー制約違反になるからです。
演習
次のテーブルは、それぞれマスターデータ / トランザクションデータ のどちらに分類されるでしょうか?
- 従業員テーブル (
employees) - 出退勤打刻テーブル (
attendance_logs) - 部署テーブル (
departments) - 給与計算結果テーブル (
payroll_results) - 給与体系テーブル (
salary_grades) - ログインログテーブル (
login_logs)
解答例
| 番号 | 分類 | 理由 |
|---|---|---|
| 1. employees | マスター | 従業員という基準情報。入社・退職時のみ更新 |
| 2. attendance_logs | トランザクション | 毎日打刻のたびに 1 件ずつ追加される履歴 |
| 3. departments | マスター | 部署という基準情報。組織改編時のみ更新 |
| 4. payroll_results | トランザクション | 月次で計算結果が追加されていく履歴 |
| 5. salary_grades | マスター | 給与体系という基準情報。年度ごとの更新 |
| 6. login_logs | トランザクション | ログインのたびに 1 件ずつ追加される |
ありがちな間違い: 「更新が多そう = トランザクション」と判断してしまうこと。会員数 10 万人の customers (顧客マスタ) は新規会員登録で毎日更新されますが、それでも 1 人につき 1 行という「基準情報」の性質を持つため、マスターデータに分類します。区別の本質は「回数の多寡 ではなく 基準情報か履歴か」です。
別解: 「メンバーシップが時間で変わるもの」(例: 部署所属履歴) は、基準情報と履歴の中間の性質を持ちます。これは「期間モデル」と呼ばれ、本ガイドでは深入りしませんが、業務システムでは頻出します。
次のうち、注文明細テーブル (order_items) に「保存しておくべき」(マスタを参照するのでなく、その時点の値を取っておくべき) ものはどれでしょうか?
- 商品名
- 単価
- 商品コード
- 顧客の現住所
- 配送先住所
- 商品のカテゴリ
解答例
スナップショットを保存すべき (= マスタの将来変更から守りたい):
- 2. 単価: 商品の価格は変動する。過去の注文金額が変わると会計上問題
- 5. 配送先住所: 顧客は引っ越しする。「過去の注文の配送先はどこだったか」は注文時点の住所
- (場合によって 1. 商品名): 商品名のリブランドや変更で過去の注文情報が分からなくなるのを防ぐ
マスタ参照で良い (= 常に最新を見たい):
- 3. 商品コード: 業務上の識別子で変わらない (変える場合はマスタごと作り直し)
- 6. カテゴリ: 集計レポート用なら「現在のカテゴリ」で問題ない (履歴を細かく見たければスナップショットも検討)
- (場合によって 4. 顧客の現住所): 注文時点の住所と現住所は区別するため、現住所は顧客マスタ参照、注文時の配送先は注文側に保存
設計の原則:「マスタの値が変わったとき、過去の値を見たい場面があるか?」を問うこと。Yes ならスナップショット、No ならマスタ参照。
ありがちな間違い: 「容量を節約するため」と全てマスタ参照にしてしまい、商品マスタの価格を変えた瞬間に過去の売上集計が変わってしまう。容量よりも整合性を優先する判断が重要です。
まとめ
この章で学んだことを整理します。
- データには「マスターデータ (辞書・基準情報)」と「トランザクションデータ (日々発生する履歴)」の 2 種類がある
- トランザクションはマスターを参照する関係になる
- 注文明細などには マスタの値をスナップショットで保存 することで、マスタの将来変更から履歴を守る
- マスターは「無効化して残す」、トランザクションは「アーカイブ → 削除」のライフサイクル
- 増え続けるトランザクションには、アーカイブ / パーティション / 集計テーブル / インデックスで対処する
本ガイド第 1 部 (基礎編) はここまでです。次の章からは設計編に入り、システム開発の流れの中でデータベース設計がどこに位置づくかを見ていきます。