公共系の案件でDB定義書を見る機会があり、「本当にこれでいいのか?」と思って調べていたらアンチパターンだった例がいくつかありました。
今回は主キーに関するアンチパターンで、web開発でも使えそうなものを調べたのでまとめたいと思います。
ユーザーからの入力値を主キーにしている
問題点
- 入力ミスなどにより、一意性が崩れる可能性がある(主キーとして機能しないので論外)
改善案
- サロゲートキーを主キーにする
ナチュラルキーを主キーにしている
問題点
- 入力値であることが多いため、意図せず変更される可能性がある(今回は入力値でした)
- 仕様変更によりキーの体系自体が変わる可能性がある
- 業務的な通し番号(注文番号など)でもNG
UUIDや長大な文字列を主キーにする
- MySQLでは文字列のインデックスは数値より重く、パフォーマンス低下につながる
- UUIDはソート順がランダムになるので、INSERT字にページ分割が頻発する
改善案
-
数値型のAUTO_INCREMENTやバイナリ形式UUID(BYNARY(16))を使用する。
-
サロゲートキーを主キーとする
サロゲートキーとは:業務知識とは直接関係のない、システム側が自動で決定するキー
複合主キー(ケースバイケース)
問題とならない場合
- 業務的に自然なキーの組み合わせで一意となる場合(テーブル定義変更の可能性や参照先が少ない場合に限る)
- 多対多の中間テーブル(student_id, course_idのstudent_courseテーブルだと、自然に「同じ学生が同じ講義を2回登録できない」という制約となり、IDの裁判が不要でシンプル)
問題となる場合
- 将来的に主キーの構成が変わる可能性がある場合(全参照テーブルで修正が必要になる)
- 複数のテーブルで参照される可能性が高い場合(外部キーで参照する側も復号キーを持たなければならず、JOINやSQL設計が煩雑になる)
- 開発でORMを利用する場合(LaravelのEloquentなど、ORMは単一カラムPKを前提としていることが多い)
理論的に複数キーの組み合わせで一意になるからと言って、複合主キーを使うべきとは限らないのがポイント。
まとめ
- 主キーは「変わらない」「短い」「機械的に一意」が理想。
- ORM使用+MySQLの現場では、「主キーはサロゲートキー(id)」+「業務上のユニーク条件は別途UNIQUE制約」で分離するのが実務的に安全。
- 自然キーやUUIDを使う場合は、ドメイン情報や機能要件の変更・パフォーマンスまで見通したうえで慎重に。