主キー設計の鉄則:自然キー vs 代理キーをどう選ぶべきか?

データベース設計の中でも、意外と悩まれるのが主キーの設計です。

特に

「自然キーで行くべきか?」
「代理キーを使うべきか?」

という問題は、現場でもよく議論になります。

一見シンプルに見える選択ですが、主キーの設計を誤ると、

  • コード体系の変更で全テーブルが壊れる
  • 複合キーが膨らんでJOINが遅くなる
  • 主キー変更で履歴データが崩壊する
  • 過去データの整合性が取れない

など、実務では取り返しのつかないトラブルに直結します。

逆に言えば、主キーの設計を正しく行うだけで、システムは圧倒的に壊れにくくなる ということです。

本記事では、

  • 自然キーと代理キーの違い
  • それぞれのメリット・デメリット
  • 実務での落とし穴
  • 結局どちらを選ぶべきか?の判断軸
  • おすすめの“鉄板パターン”

を図解しながらわかりやすく整理していきます。

SQL初心者の方はもちろん、業務システムの設計に関わる方にも役立つ内容になっていますので、
ぜひ最後まで読んでみてください。

目次

主キーとは何か?

自然キーと代理キーの違いを理解する前に、まずは「主キーとは何なのか?」をシンプルに整理しておきます。

主キーは、テーブルの中で”1行を一意に識別するための値”のことです。

DBの世界では、膨大なデータの中から正しい1行を特定できなければ、更新も削除も正しく行えません。

その”住所”として機能するのが主キーです。

主キーが満たすべき条件

主キーは、次のような重要な性質を持っています。

一意であること(重複しない)

同じ値が2行存在してはいけません。
重複すると、どちらが正しいデータなのかDBが判断できなくなります。

NULLにならないこと

「存在しない」状態を許すことはできません。
NULLだと”行の住所が不明”になってしまいます。

変わらないこと

主キーの値は基本的に変更すべきではありません。
変更すると、外部キーで結びついている他のテーブルにも影響が波及します。

自然キーとは

自然キーとは、“すでに存在している業務上の属性”を、そのまま主キーに利用する方式
のことです。別名「業務キー」「ビジネスキー」と呼ばれることもあります。

自然キーの具体例

実務でもおなじみの値がそのまま主キーになります。

  • 社員番号
  • 商品コード
  • 顧客コード
  • ISBN
  • 口座番号
  • 都道府県コード

これらは、業務で意味を持つ識別子であり、
現場の人が見ても「これがキーだね」とすぐ理解できます。

自然キーのメリット

業務的な意味を持っていて読みやすい

「社員番号 000123」や「商品コード A-9999」など、
そのキーだけで“何の行か”を想像しやすいのは自然キーの強みです。

ドメイン知識とDB構造がズレにくく、現場の担当者も理解しやすい点は大きなメリットです。

追加の列を増やす必要がない

意味のある業務属性をそのままキーに使うため、
新たに ID カラムを作らなくてよい場合があります。

→ テーブルをシンプルに保てる場面もある。

JOINが自然で、SQLが読みやすい

商品コード同士で結ぶ、社員番号同士で結ぶ…など、JOINの意味が明確になります。

SELECT *
FROM orders o
JOIN products p ON o.product_code = p.product_code;

業務に馴染んだSQLを書きやすい点も魅力です。

自然キーのデメリット

実はこのデメリットが原因で「代理キー(ID)で行こう」という判断になることが多いです。

変更される可能性がある

商品コード体系が変わった、社員番号ルールが変わった…
業務では“キーが変わる”ことは普通に発生します。

主キーが変わると、以下のように致命的な問題が起こります。

  • 外部キーを張っている全テーブルに影響
  • 100万行単位のUPDATEが必要
  • 履歴データが壊れる
  • 予期せぬ参照エラーが連発

主キーは“変わらない”ことが前提なので、ここが大きなリスクになります。

複合主キーになりがちでテーブルが複雑化

業務上の自然キーは1つとは限らず、複数属性で一意になるケースが多いです。

例)

  • 店舗コード + レジ番号
  • 年度 + 部署コード + 社員番号
  • 日付 + 明細番号

こうなると、

  • 主キーが複合になって読みづらい
  • 外部キーの列が増えて重くなる
  • JOIN が複雑化

といった問題が発生します。

外部キーが重くなり、パフォーマンスに影響

複合キーを参照する外部キーは非常に重く、バッチ処理や集計処理でパフォーマンスが落ちやすくなります。

代理キーとは

代理キーとは、業務的な意味を持たない”人工的な主キー”のことです。

システムが自動採番したり、UUIDを生成して主キーに利用します。
多くのシステムで使われている”idカラム”がまさに代理キーです。

代理キーの具体例

実務でよく使われるものはこちら

  • Auto Increment(1, 2, 3, … と増えていく ID)
  • シーケンス番号(PostgreSQL / Oracleなど)
  • UUID(ランダムまたは時系列キー)
  • ULID / NanoID(新しい世代の識別子)

これらの値は 業務とは無関係で、ただ行を一意にするためだけ に存在します。

代理キーのメリット

自然キーと違い、代理キーは「主キーとして理想的な特性」を持っています。

変更が絶対に発生しない

業務意味を持たないため、コード体系変更などの影響を一切受けません。

主キーに必要な 不変性(変更されないこと) が担保されるため、

  • 外部キーが壊れない
  • 履歴テーブルの整合性も守られる
  • 将来の業務変更に強い

といった安心感があります。

単純な1列で完結する

代理キーの主キーは通常 1 列です。

  • SQL がシンプル
  • JOIN が軽い
  • 複合キーより圧倒的に扱いやすい
  • 外部キー列も軽くてパフォーマンスが良い

複合キー地獄を避けられるのは大きなメリットです。

業務属性の変更・拡張に強い

将来的に「商品コード体系が変わりました」「社員番号を廃止します」といった変更が発生しても、

主キーは一切影響を受けません。

DB設計の長寿命化につながります。

代理キーのデメリット

もちろん万能ではなく、注意点もあります。

人が見ても何を表すのかわからない

ID=123 と表示されても、それが何を表すのか人間にはわかりません。
(ログ確認や調査時に不便なことがあります)

列が1つ増える

自然キーをそのまま主キーにできる場合は列が1つで済みますが、
代理キーを使うと 業務キー + ID の組み合わせになります。

業務上の自然キーにもユニーク制約を付け忘れる事故が起こる

代理キーを採用するときに最も多いミスがこれです。

ID は重複しないけど、商品コードは重複してしまった
という不整合が発生します。

そのため、代理キー採用時は、

  • ID ⇒ PK
  • 商品コードなどの業務キー ⇒ UNIQUE制約を付与

というセット運用が必須です。

自然キー vs 代理キーの比較表

自然キーと代理キーの違いを一目で理解できるように、以下の表に整理しました。

スクロールできます
比較項目自然キー(Natural Key)代理キー(Surrogate Key)
定義業務上の意味を持つ既存属性を主キーにするシステムが生成した人工的なIDを主キーにする
社員番号、商品コード、ISBNID、Auto Increment、UUID
意味の有無人間が見て意味が分かる人間には意味が分からない(システム用)
変更耐性業務変更で壊れやすい不変で安心(変更されない)
列数単一または複合になりがち基本は単一
外部キー負荷複合キーの場合 JOIN が重いJOIN が軽くシンプル
履歴管理主キー変更で履歴が壊れるリスク履歴管理が容易(ID固定)
運用コスト業務ルール変更で負荷が高い安定して長期運用可能
SQL 可読性業務理解がしやすいJOIN は直感的で軽いが意味は不明

ポイント

  • 小規模システムで変更がほぼない場合 → 自然キーでもOK
  • ほとんどの業務システム → 代理キー推奨
  • 代理キー採用時は、業務キーに必ず UNIQUE 制約を付与する

まとめ

主キー設計は、データベースの安定性や運用のしやすさに直結する重要なポイントです。
本記事では、自然キーと代理キーの違い、メリット・デメリット、実務での落とし穴まで整理しました。

ポイントを改めてまとめると、

  • 自然キーは業務的に意味がわかりやすく直感的だが、業務変更に弱い
  • 代理キーは不変で扱いやすく、長期運用や履歴管理に強い
  • 実務では 代理キーを主キーにして、自然キーは別カラムでUNIQUE制約 を付与するのが鉄板パターン

この設計ルールを押さえておけば、将来的な業務変更やシステム拡張の際もトラブルを避けやすくなります。

データベース設計の基本でありながら見落とされがちな 主キー設計
ぜひ本記事を参考にして、あなたのシステムでも安全でメンテナンスしやすい設計を実践してみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

沖縄出身のエンジニアです。IT業界で5年以上の経験があり、主にC#やPHPを使って開発を行ってきました。新しい技術にも興味があり、日々学びながらスキルアップを目指しています。

コメント

コメントする

CAPTCHA


目次