データベース
SQLアンチパターン
主キー
PrimaryKey
More than 3 years have passed since last update.

データベースを作るときに、多くの場合「主キー」をつけます。ただ、この「主キー」を、あまり考えなしにつけてしまうと、あとあと厄介なことになります。


大原則

主キーは、テーブル内のレコードを識別して、紐付けるための値です。主キーが持つべき性質として、


  • 重複しない:主キーが重複してはレコードの識別子でなくなってしまいますので、これは絶対条件です。

  • 扱いやすい:レコードを参照するのに、いちいち100文字の主キーで参照するのでは骨が折れます。

  • 永続的:レコードが一度作られれば、そこに振られた主キーは中身が変化しようとも変化せず、レコードを削除しても再利用すべきではありません。

のようなものがあります。なお、RDBMSの実装上使いやすいので、主キーを連番として自動的に振ることがありますが、「連番である」ことは主キーの本質と特に関係ありません。


外部の都合で変化・重複しうるものを主キーにしない

氏名・住所・電話番号1・生年月日・メールアドレス1といった値は、同じものが発生しうる上に、外的要因で変化するので、主キーとして使うのに適切ではありません。「会員番号」のような一意な値を内部で生成して、それを主キーにしましょう。


主キーが連番なことを期待しない

そもそも上で述べたように、主キーは本質的に連番である必要はありませんし、たとえ連番モードにしていても状況によっては飛ぶことがありえます。さらに、削除した項目について主キーを再利用すべきではないので(SQLアンチパターン21章、シュードキー・ニートフリーク)、自然とキーは飛んでいきます。主キーが連続であることに依存しないような処理を行いましょう。

日本の法律でも、例えば刑法200条は「削除」とだけなっています。これは、かつてここにあった尊属殺人罪に違憲判決が出たため、刑法現代語化の際に条文を削ったのですが、そのまま削るだけだとあとの条文番号がずれてしまって、刑法のこれ以降の条項を参照するすべての法律を書き換える必要が出てきてしまうので、「第200条 削除」として番号は消費したままとなっています。


主キーに項目識別以上の機能を持たせない

番号にした主キーでも、ときどき番号自体を意識的に振ることで、番号自体に意味をもたせることがありますが、そのようなことをすると行き詰まるケースも多々あります。

たとえば、東京証券取引所など日本の株式市場へ上場している企業には、4桁の数字で「証券コード」が振られています。元々は番号を区分してどのような業種なのかという意味をもたせていたのですが、10000しか番号がないところに東証だけで3500社近くが上場しているため、番号帯による区分が適用できない企業も増加しています。

また、自分が開発していたシステムでの話ですが、選択項目のリストを別テーブルに持たせていました。そして、意識的に主キーで順番を振って、ソートもその順で行なっていたのですが、主キーを連番で振った項目の途中にあとから項目を追加する必要が出てきてしまいました。主キーを動かすのも他所への影響が出そうなので断念して、結局「整列用の順序を別な列に入れて、追加項目の主キーは別な位置にする」という方法で乗り切ることにしました。ということで、「特定の順序を作るために主キーを使う」のも破綻をきたすことがあります。


複合主キー

複数列の組み合わせでレコードを確定させる「複合主キー」という機能もあります。ただ、これをやる際にも主キーに含まれるすべての列が外的に変更されないものでないと、厄介なことになります。使える場面としては、


  • 多対多対応の中間テーブルについて、両テーブルを参照する主キーの組で複合主キーとする(SQLアンチパターン3章、IDリクワイヤド参照)

  • 「登録した年月日(など)」+「一意な番号など」のような組み合わせ

など、限られたものになるとは思います。


例外

郵便番号、ISBNコード、JANコード、市区町村コードのように、誰かがコード体系を構築していることがあります。このような体系を取り入れて使う場合、マスターデータの主キーにはこれらのコードそのものを振るのが適当です。もちろん、内部で参照する場合は(そのコード体系と一対一で対応させたいのでなければ)別に振りなおしても構いません。


参考文献





  1. 当然ながら、これらはサービスを提供する側では一意なので、そちらのシステムでは使ってもいいかもしれません。