Hot Heart, Cool Mind.

会計×IT の深層へ

主キーの設計①

主キー論争(データベース設計で、どういうものをテーブルの主キーとすべきかという議論)が再燃しているようだ(こことかこことかこことかここ)。


これはかなり以前からある論争で、大雑把にいうとコード派とID派という二つの立場の間で戦われている。

  • コード派 … ユーザの目に触れるデータ項目(典型的にはコード)を主キーとする。複合主キーを許す。
  • ID派 … ユーザの目に触れないデータ項目(自動生成したID)を主キーとする。複合主キーを許さない。

僕としてはいずれも一長一短あると思うのだが、両派なんとなく主張がすれ違っているようにも見える。やはりまず、主キーとは何かというところに立ち戻って考えないと、論点が見えにくくなるんじゃないだろうか。

主キーには以下の二つの機能がある。

  1. ユーザーからコンピュータシステムに対する要求において、対象データを一意に指定する手段を提供する(外部識別子機能)
  2. エンティティ間の結びつきを表現する手段を提供する。すなわちUMLでいう「関連(アソシエーション)」の実装手段としての機能(内部識別子機能)
この二つの機能は本来別のものなのだが、リレーショナルモデルでは、あえて両方を主キーに担わせている。これは、コッド博士によってリレーショナルモデルが考案された当初、過去の階層型データベースやネットワークデータベースへのアンチテーゼとして性格づけられていたためだと思う。リレーショナル以前のデータベースでは二つの機能はそれぞれ異なる仕組みで実現されていたのである。
コッド博士の1970年の記念碑的論文「A Relational Model of Data for Large Shared Data Banks」からちょっと引用してみよう。

In previous work there has been a strong tendency to treat the data in a data bank as consisting of two parts, one part consisting of entity descriptions (for example, descriptions of suppliers) and the other part consisting of relations between the various entities or types of entities (for example, the supply relation). This distinction is difficult to maintain when one may have foreign keys in any relation whatsoever. In the user's relational model there appears to be no advantage to making such a distinction (there may be some advantage, however, when one applies relational concepts to machine representations of the user's set of relationships). --- P.380

(拙訳)
先行研究においては、データバンク中のデータを二つの部分から構成されるものとして取り扱う強い傾向が存在した。すなわち、ひとつ目の部分はエンティティの記述項目(例えば、仕入先に関する記述項目)[訳注①]から成り、他の部分はさまざまなエンティティやエンティティタイプの間の関係(例えば、仕入関係)[訳注②]から成るとするのである。任意のリレーションに外部キーを設けてよいとするなら、それがどんなものであれ、この区別[訳注③]を維持することは困難となる。ユーザー向けのリレーショナルモデルでは、こうした区別を設けることに利益は無いように見える(とはいえ、ユーザー向けのリレーションシップ[訳注④]の集合に対する計算機上の表現にリレーショナル概念を適用する際には、いくらかの利益があるかもしれない)。

[訳注①]UMLで言う「属性」
[訳注②]UMLで言う「関連(アソシエーション)」
[訳注③]二つの部分(UMLでいう「属性」と「関連」)の区別のこと
[訳注④]本論文では、「リレーション」と「リレーションシップ」はほぼ同義で、RDBの「テーブル」に相当するものを指す。

補足するなら、階層型データベースやネットワークデータベースでは「関連」はポインタなどで実装され、「属性」とは扱いが異なっていた。このことにより、データベース設計時に想定していなかったアクセスパスでのデータアクセスは困難であった(「アクセスパス依存」)。それで、コッド博士は、属性と関連を統一的に扱えるモデルとして、リレーショナルモデルを考案したのである。具体的には、エンティティを一意に識別する主キーの存在を前提とし、それを用いて関連を表現することにした訳だ。

これについて僕の感想を言えば、属性と関連を統一的に扱うのは卓見だったと思うが、ポインタ(他エンティティへの参照)を排除してしまったのは、やりすぎだったような気がしてならない。属性として「参照型(ポインタ型)」を許すという形での解決があり得たはずである。このような解決アプローチを採らなかった理由は、上記論文にははっきり書いていないが、たぶんユーザー志向を徹底したかったのだろう。こんな文章がある:

It[訳注①] provides a means of describing data with its natural structure only--that is, without superimposing any additional structure for machine representation purposes. Accordingly, it provides a basis for a high level data language which will yield maximal independence between programs on the one hand and machine representation and organization of data on the other. --- P.377

(拙訳)
リレーショナルモデルは、データの自然な構造だけをもちいて、つまり、計算機上の表現のための構造をいっさい付け加えることなくデータを記述する手段を提供する。その結果として、リレーショナルモデルは、プログラムの側と計算機上のデータ表現およびデータ編成の側の間に最大限の独立性をもたらす高水準の言語にとっての基礎を提供するのである。

[訳注①] この文章の少し前にある "the relational view( or model )" を指す。

こうした立場からは、ポインタは、排除すべき「計算機上の表現のための構造」ということになるのだろう。 参考までに、C.J.デイト氏の「データベース実践講義」にはこんな文章がある:

...次に、データベースの関係[注①]はどのようなものであろうとポインタ型の属性を持つことはできない。知ってのとおり、リレーショナルデータベースが登場する以前のデータベースはポインタだらけで、そうしたデータベースにアクセスするためには多くのポインタをたどっていかなければならなかった。アプリケーションのプログラミングにエラーが多く、エンドユーザーから直接アクセスすることが不可能だったのには、そうした事情があった。Coddはリレーショナルモデルでそうした問題を解決しようとし、もちろんそれに成功したのである。 --- P.39

[注①] リレーションすなわちテーブルのこと

こうした理由で、リレーショナルモデルからポインタ型は排除され、主キーが外部識別子と内部識別子の両方の機能を担うことになったわけである。

こういう風に考えると、ユーザの目に触れない自動生成IDを主キーとして使用するというID派の主張は、リレーショナルモデルにおいてポインタ型(あるいはもっと含みのある言い方をすれば「参照型」)の復権を図る試みとして理解できる。この試みに対して、C.J.デイト氏は以下のように反対している。

...これらの行IDがオブジェクト指向の意味において何らかのオブジェクトIDと見なされるとしたら、行IDは間違いなく禁止されるのである(SQL規格と主なSQL製品のほとんどでは、実に残念なことに、そのように見なされている)。オブジェクトIDは実質的にポインタであり、リレーショナルモデルではポインタを明示的に禁止している。--- 前掲書P.74

この文章はコッド博士の考えを極めて明晰に代弁しているように思える。しかし同時に、ちょっと極論のような気もする。というのは、IDを許さないことによるデメリットも間違いなく存在するからだ。これには以下の2つがある。

  1. 主キー値の変更の影響が広範囲に波及しやすくなる。… ある商品の商品コードを変更すると、商品テーブルを外部参照しているすべてのテーブル(例えば受注明細テーブル)上の商品コード値を洗い替えなければならない(ちなみに、意外かもしれないが、リレーショナルモデルでは主キー値の変更は禁止されていない。もちろん設計上禁止することはできるが)。
  2. 主キーの構成の変更の影響が広範囲に波及しやすくなる。…商品テーブルの主キーを「商品コード」から「会社コード+商品コード」に変更した場合、商品テーブルを外部参照しているすべてのテーブルの構造に変更が必要となる。
上記の2つの問題は、ID(実質的ポインタ)を使用すれば解決できる。

関連の実装としてのポインタを許したとしても、それを属性項目と同列に扱うという核心的規則が維持されるなら、リレーショナルモデルの目標であったアクセスパス依存の排除は依然として達成できる。犠牲になるのは「データの自然な構造だけを用いたデータ記述」という部分であるが、ユーザーがSQLで直接検索しない多くのデータベースではこのことの重要性がさほど高いとは思われない。

以上を考慮すればIDを使用すべきかどうかはなんらかの基本セオリーにもとづいて決められることではなく、トレードオフにもとづいて判断する種類のことと言うべきだ。
たとえば、判断するのが僕なら、ほとんどのケースにおいては内部識別子の機能をIDにゆだねる方を選ぶ。エンドユーザーがSQL(やSQLベースのクエリツール)で直接操作するデータベースなどでは、コードによる主キーを用いることを考慮するかもしれない。

ここまでで、設計結果としてのデータベースにおいて、どういうものをテーブルの主キーとすべきか、という問題にはほぼ結論が出たと思う(外部識別子の設計問題など、残された若干の問題については後日触れたい)。しかしこれだけでは事態は収拾しないのである。状況を複雑にしているのは、この問題に、データベースの設計手法についての議論が重なっていることである。その背景には、リレーショナルモデルの設計基準である「正規形」の概念が、コッド博士の定義した二重人格の主キー概念と深くむすびついているという事情がある。このために、正規形ないしその基礎にある関数従属性の概念を重視する人々(じっさい関数従属性の概念は重視してしかるべきだ)は、複合主キーを許容する方向(コード派)に傾くのである。
だからID派とコード派の意見の相違は、最終的にできあがるデータベースの形に関するものというよりも、コッド博士の関数従属性の概念にどれほど忠実であるか、という点に端を発しているように思えてならない。
次回は、この点について検討してみたい。