主キーに変更される可能性のある列を入れるべきか
例えば以下の様なDBテーブルがあります。
CREATE TABLE Member
(
ID INT IDENTITY PRIMARY KEY,
Name NVARCHAR(10),
Status TINYINT,
CONSTRAINT UN_MainNameStatus UNIQUE(Name, Status)
)
CREATE TABLE Info
(
Name NVARCHAR(10),
Status TINYINT,
InfoNunber INT,
InfoBody NVARCHAR(50),
PRIMARY KEY(Name, Status, InfoNunber)
)
ここで、Member
テーブルのStatus
は更新される可能性があります。また、Info
のName
とStatus
はプログラムレベルで一致させています。問題は現状だとMember
のStatus
更新時にInfo
の古いデータを削除し、新しいステータスに変更したコピーデータを代入しなければならない点です。この場合、Infoの主キーのName
とStatus
をID
に変更すれば外部キー制約が利用できるようになり、Member
テーブルと同時に更新する必要(データ破壊のリスク)が無くなり、DB更新も速くなると思うのですが、いかがでしょうか。
Info
テーブルのName
列とStatus
列をID
に置き換えても構わないのなら、置き換えたほうが良いと思う。
さらにいうと、私はサロゲートキー原理主義なので、ID
とMemberID
を用意し、Member.ID
とInfo.MemberID
で外部制約を組み、Info.ID
は主キーとしての責務に励んでもらいます(過激派)。
Info
のName
とStatus
をMember
の同項目と同じ値に保ちたいのであれば、外部制約を作成してON UPDATE CASCADE
を指定すれば出来るでしょう。
それとは別に、更新される項目を主キーに含めるのは避けた方が良いでしょう。
データベース側の視点としては主キーのインデックスの再構成が走ることになりパフォーマンス面でよくありませんし、
アプリゲーション側の視点では、ORM等を利用する場合に問題が出る場合があります。
例えば、EntityFrameworkを利用した場合に自動的にUPDATE処理の実装が作成されますが、主キーが更新されることを想定していないので主キーを更新する場合に自動生成処理は利用できません(生SQLを発行して独自に更新処理を用意する必要が出てきます)。
同様に、DBから自動的にSQLを生成するようなフレームワークを利用する場合も生成されたSQLがそのまま利用できないことも考えられます。
(多くのフレームワークでは主キーを更新することはBad Practice扱いです)
@ktz_alias さんが言っていますが、IDを利用できるのであればIDを利用するのが無難でしょう。
まぜっかえすようなコメントで申し訳ないのですが、しっかりしたテーブル設計(データモデリング)ができていれば、主キーを構成する列にUpdateが発生することは、基本的にないはずです。(Inser/Deleteしか発生しないのが基本)
ですので、「主キーに変更される可能性のある列を入れるべきか」ではなく、「なぜ主キーに更新が発生する設計になっているか」を考え、修正すべきです。
提示いただいた情報からだけでは、どういう業務モデルを想定しているのかわかりませんが、少なくとも、「Member」というテーブルの主キーが「Name」と「Status」で構成されるのはおかしいです。
(NameとStatusでユニークキーを構成しているのは、これが論理的な主キー(ビジネスキー)だという意味であっていますよね?)
おかしい理由は、Memberというテーブルは、その名称から考えて、メンバー1名が1レコードになるテーブルであるはずなのに、1名に対してStatusの分、複数レコードが生成されてしまうこと、です。
想定している業務モデル次第ですが、たとえば、以下のような設計が修正案になりうるかと思います。
CREATE TABLE Member
(
Name NVARCHAR(10),
Birthday date,
Gender int,
CONSTRAINT PK_Member PRIMARY KEY(Name)
)
CREATE TABLE MemberStaus
(
Name NVARCHAR(10),
Status TINYINT,
CONSTRAINT PK_MemberStatus PRIMARY KEY(Name, Status)
)
CREATE TABLE MemberAttribute
(
Name NVARCHAR(10),
AttributeType INT,
AttributeValue NVARCHAR(50),
CONSTRAINT PK_UserAttribute PRIMARY KEY(Name, AttributeType)
)
ID列(サロゲートキー)の話は、この辺りを整理した後で、考えればよいかと。