繰り返しますが、古い議論がまだ発生しています...
ビジネス キーをプライマリ キーとして使用する方がよいでしょうか。それとも、ビジネス キー フィールドに一意の制約があるサロゲート ID (つまり、SQL Server の ID) を使用する方がよいでしょうか。
あなたの理論を裏付ける例または証拠を提供してください。
繰り返しますが、古い議論がまだ発生しています...
ビジネス キーをプライマリ キーとして使用する方がよいでしょうか。それとも、ビジネス キー フィールドに一意の制約があるサロゲート ID (つまり、SQL Server の ID) を使用する方がよいでしょうか。
あなたの理論を裏付ける例または証拠を提供してください。
代理キーを使用する理由はいくつかあります。
安定性:ビジネスまたは自然なニーズのためにキーを変更すると、関連するテーブルに悪影響を及ぼします。値に関連付けられた意味がないため、代理キーを変更する必要はほとんどありません。
規則:PKのさまざまな名前でテーブルを結合する方法を考える必要がなく、標準化された主キー列の命名規則を使用できます。
速度:PK値とタイプによっては、整数のサロゲートキーが小さくなり、インデックス作成と検索が高速になる場合があります。
両方。ケーキを持って食べてください。
主キーにはそのようにラベルが付けられていることを除いて、特別なことは何もないことを忘れないでください。これはNOTNULLUNIQUE制約にすぎず、テーブルには複数の制約を含めることができます。
代理キーを使用する場合でも、ビジネスルールに従って一意性を確保するためのビジネスキーが必要です。
非代理 (「自然」と言うのはためらう) キーをサポートすることについて、まだ誰も何も言っていないようです。だからここに行きます...
代理キーの欠点は、それらが無意味であることです(一部では利点として挙げられていますが...)。これにより、実際に必要な数よりも多くのテーブルをクエリに結合する必要が生じることがあります。比較:
select sum(t.hours)
from timesheets t
where t.dept_code = 'HR'
and t.status = 'VALID'
and t.project_code = 'MYPROJECT'
and t.task = 'BUILD';
に対して:
select sum(t.hours)
from timesheets t
join departents d on d.dept_id = t.dept_id
join timesheet_statuses s on s.status_id = t.status_id
join projects p on p.project_id = t.project_id
join tasks k on k.task_id = t.task_id
where d.dept_code = 'HR'
and s.status = 'VALID'
and p.project_code = 'MYPROJECT'
and k.task_code = 'BUILD';
誰かが真剣に考えている場合を除いて、次のことは良い考えですか?:
select sum(t.hours)
from timesheets t
where t.dept_id = 34394
and t.status_id = 89
and t.project_id = 1253
and t.task_id = 77;
「しかし、MYPROJECT、VALID、または HR のコードが変更されるとどうなるでしょうか」と誰かが言うでしょう。私の答えは、「なぜそれを変更する必要があるのですか?」です。これらは、今後「有効」を「良い」として再コード化する必要があることを何らかの外部機関が立法しようとしているという意味で、「自然な」キーではありません。「自然な」キーのごく一部だけが実際にそのカテゴリに分類されます。SSN と郵便番号が通常の例です。Person、Address などのテーブルには無意味な数値キーを使用しますが、すべてではありません。何らかの理由で、ここのほとんどの人が支持しているようです。
参照:別の質問に対する私の回答
サロゲート キーを変更する理由はありません。自然キーについても同じことは言えません。姓、電子メール、ISBN 番号 - それらはすべて 1 日で変わる可能性があります。
サロゲートキー(通常は整数)には、テーブルリレーションを高速化し、ストレージと更新速度をより経済的にするという付加価値があります(さらに良いことに、ビジネスキーフィールドとは対照的に、サロゲートキーを使用するときに外部キーを更新する必要はありません。それは時々変化します)。
テーブルの主キーは、主に結合の目的で、行を一意に識別するために使用する必要があります。Personsテーブルを考えてみてください。名前は変更される可能性があり、一意であるとは限りません。
企業を考える:あなたはメルキアの他の企業とビジネスをしている幸せなマーキン企業です。あなたは会社名を主キーとして使用しないのに十分賢いので、10文字の英数字全体でMerkiaの政府の一意の会社IDを使用します。次に、Merkiaは会社IDを変更します。これは、Merkiaが良いアイデアだと考えたためです。そもそもあなたを巻き込むべきではない変更のために、dbエンジンのカスケード更新機能を使用しても大丈夫です。その後、あなたのビジネスは拡大し、今あなたはフリードニアの会社で働いています。Freedonianの会社IDは最大16文字です。会社IDの主キー(Orders、Issues、MoneyTransfersなどの外部キーフィールドも)を拡大し、主キー(これも外部キー)にCountryフィールドを追加する必要があります。痛い!フリードニアの内戦、それは」sは3か国に分かれています。アソシエイトの国名を新しい国名に変更する必要があります。レスキューへのカスケード更新。ところで、あなたの主キーは何ですか?(国、CompanyID)または(CompanyID、国)?後者は参加を支援し、前者は別のインデックスを回避します(または、注文を国ごとにグループ化する場合は、おそらく多くのインデックスを使用します)。
これらはすべて証明ではありませんが、結合操作を含むすべての用途で行を一意に識別するための代理キーが、ビジネスキーよりも望ましいことを示しています。
私は一般的に代理キーが嫌いです。これらは、利用可能な高品質の自然キーがない場合にのみ使用する必要があります。あなたがそれについて考えるとき、あなたのテーブルに無意味なデータを追加することが物事をより良くすることができると考えることはかなりばかげています。
これが私の理由です:
自然キーを使用する場合、テーブルは最も頻繁に検索される方法でクラスター化されるため、クエリが高速になります。
代理キーを使用する場合は、論理キー列に一意のインデックスを追加する必要があります。それでも、論理的な重複データを防ぐ必要があります。たとえば、pkが代理ID列であっても、Organizationテーブルに同じ名前の2つの組織を許可することはできません。
代理キーが主キーとして使用される場合、自然の主キーが何であるかははるかに明確ではありません。開発するときは、どの列のセットがテーブルを一意にするかを知りたいと思います。
1対多の関係チェーンでは、論理キーチェーン。したがって、たとえば、組織には多くのアカウントがあり、アカウントには多くの請求書があります。したがって、Organizationの論理キーはOrgNameです。Accountsの論理キーは、OrgName、AccountIDです。請求書の論理キーは、OrgName、AccountID、InvoiceNumberです。
代理キーが使用される場合、キーチェーンは、直接の親への外部キーのみを持つことによって切り捨てられます。たとえば、請求書テーブルにはOrgName列がありません。AccountIDの列のみがあります。特定の組織の請求書を検索する場合は、[組織]、[アカウント]、および[請求書]テーブルに参加する必要があります。論理キーを使用する場合は、組織テーブルを直接クエリできます。
ルックアップテーブルの代理キー値を保存すると、テーブルが無意味な整数で埋められます。データを表示するには、すべてのルックアップテーブルに結合する複雑なビューを作成する必要があります。ルックアップテーブルは、列の許容値のセットを保持することを目的としています。代わりに整数の代理キーを格納することによって体系化するべきではありません。正規化ルールには、値自体の代わりに代理整数を格納する必要があることを示唆するものはありません。
私は3つの異なるデータベースの本を持っています。それらの1つは、代理キーを使用していることを示していません。
ビジネス上の意味を持たないキーを常に使用してください。それはただの良い習慣です。
編集: オンラインでリンクを見つけようとしましたが、できませんでした。しかし、'Patterns of Enterprise Archtecture' [Fowler] には、キーであること以外に意味のないキー以外のものを使用してはならない理由がよく説明されています。要するに、1 つのジョブと 1 つのジョブのみを持つ必要があるという事実です。
ORMツールを使用してデータクラスを処理/生成する予定がある場合、代理キーは非常に便利です。より高度なマッパー (休止状態) の一部で複合キーを使用できますが、コードが複雑になります。
(もちろん、データベースの純粋主義者は、代理キーの概念でさえ忌まわしいと主張するでしょう。)
私は、適切な場合に代理キーに uid を使用するのが好きです。それらの主な利点は、事前にキーを知っていることです。たとえば、ID が既に設定されており、一意であることが保証されているクラスのインスタンスを作成できますが、整数キーを使用すると、デフォルトを 0 または - にする必要があります。 1 にして、保存/更新時に適切な値に更新します。
ただし、UID にはルックアップと結合速度の点でペナルティがあるため、それらが望ましいかどうかは問題のアプリケーションによって異なります。
私の意見では、代理キーを使用する方が良いです。変更される可能性はゼロだからです。自然キーとして使用する可能性があると私が考えることができるほとんどすべてが変更される可能性があります(免責事項:常に真実であるとは限りませんが、一般的です)。
例として、車の DB があります。一見すると、ナンバー プレートがキーとして使用できると考えるかもしれません。しかし、これらは変更される可能性があるため、それは悪い考えです。アプリをリリースした後、誰かが自分のナンバー プレートを光沢のある新しいパーソナライズされたナンバー プレートに変更できない理由を知りたがっているときに、それを知りたいとは思わないでしょう。
可能であれば、常に単一の列、代理キーを使用してください。これにより、レコードを維持するために単一の情報を追跡するだけの責任があるため、結合と挿入/更新/削除がよりクリーンになります。
次に、必要に応じて、ビジネス キーを一意の制約またはインデックスとしてスタックします。これにより、データの整合性が保たれます。
ビジネス ロジック/自然キーは変更できますが、テーブルの物理キーは決して変更しないでください。
Case 1: Your table is a lookup table with less than 50 records (50 types)
In this case, use manually named keys, according to the meaning of each record.
For Example:
Table: JOB with 50 records
CODE (primary key) NAME DESCRIPTION
PRG PROGRAMMER A programmer is writing code
MNG MANAGER A manager is doing whatever
CLN CLEANER A cleaner cleans
...............
joined with
Table: PEOPLE with 100000 inserts
foreign key JOBCODE in table PEOPLE
looks at
primary key CODE in table JOB
Case 2: Your table is a table with thousands of records
Use surrogate/autoincrement keys.
For Example:
Table: ASSIGNMENT with 1000000 records
joined with
Table: PEOPLE with 100000 records
foreign key PEOPLEID in table ASSIGNMENT
looks at
primary key ID in table PEOPLE (autoincrement)
In the first case:
PEOPLE
without use of join with table JOB
, but just with: SELECT * FROM PEOPLE WHERE JOBCODE = 'PRG'
In the second case:
データ ウェアハウスのシナリオでは、代理キー パスに従う方がよいと思います。2 つの理由:
代理キーは、ビジネス情報が変更または同一である可能性がある場合に役立ちます。結局のところ、商号は全国で一意である必要はありません。カンザス州とミシガン州に 1 つずつ、Smith Electronics という名前の 2 つの企業を扱っているとします。住所で区別できますが、それは変わります。状態も変わる可能性があります。カンザス州カンザスシティーのスミス・エレクトロニクスが川を渡ってミズーリ州カンザスシティーに移転したら? これらのビジネスを自然なキー情報で区別する明確な方法はないため、代理キーは非常に便利です。
代理キーは ISBN 番号のようなものと考えてください。通常、本はタイトルと著者で識別します。しかし、HP Willmott の「Pearl Harbor」というタイトルの本を 2 冊持っていますが、これらは版が違うだけでなく、明らかに別の本です。そのような場合、本の外観を参照したり、古いものと新しいものを参照したりできますが、頼りになる ISBN があることも同様です。
これは、代理キーがほぼ常に意味を持つケースの 1 つです。データベースに最適なもの、またはオブジェクト モデルに最適なものを選択する場合もありますが、どちらの場合も、無意味なキーまたは GUID を使用することをお勧めします。これにより、インデックス作成がより簡単かつ高速になり、変更されないオブジェクトの ID になります。
SQL Server にはこれらのデータを物理的に並べ替える機能がないため、クラスター化されたインデックスをランダム サロゲート キー、つまり XY8D7-DFD8S を読み取る GUID に配置することはお勧めできません。代わりに、これらのデータに一意のインデックスを配置する必要がありますが、メイン テーブル操作に対して SQL プロファイラーを実行し、それらのデータをデータベース エンジン チューニング アドバイザーに配置することも有益な場合があります。
ポイント イン タイム データベースの場合は、代理キーと自然キーを組み合わせるのが最適です。たとえば、クラブのメンバー情報を追跡する必要があります。メンバーの一部の属性は変更されません。たとえば、生年月日ですが、名前は変更できます。したがって、member_id サロゲート キーを使用して Member テーブルを作成し、DOB の列を作成します。person name という別のテーブルを作成し、member_id、member_fname、member_lname、date_updated の列を持ちます。このテーブルでは、自然キーは member_id + date_updated になります。
コース用馬。私の偏見を述べます。私は最初は開発者なので、主にユーザーに実用的なアプリケーションを提供することに関心があります。
私は自然キーを持つシステムに取り組んできましたが、値の変更が波及することを確認するために多くの時間を費やさなければなりませんでした。
私は代理キーのみを使用するシステムで作業しましたが、唯一の欠点は、パーティショニング用の非正規化データがないことです。
私が一緒に仕事をしたほとんどの従来の PL/SQL 開発者は、結合ごとのテーブルの数のために代理キーを好まなかったのですが、私たちのテストおよび本番データベースは決して汗をかきませんでした。余分な結合は、アプリケーションのパフォーマンスに影響しませんでした。「Xa = Yb 上の X 内部結合 Y」のような句をサポートしないデータベースの方言、またはその構文を使用しない開発者の場合、代理キーの余分な結合によってクエリが読みにくくなり、入力と入力に時間がかかります。チェック: @Tony Andrews の投稿を参照してください。しかし、ORM やその他の SQL 生成フレームワークを使用している場合は、それに気付かないでしょう。タッチタイピングも軽減されます。
このトピックに完全に関連しているわけではないかもしれませんが、代理キーを扱っている頭痛の種です。オラクルが事前に提供する分析は、ウェアハウス内のすべてのディメンション テーブルで自動生成された SK を作成し、それらをファクトにも格納します。そのため、新しい列が追加されたり、ディメンション内のすべてのアイテムにデータを入力する必要があるときにディメンション (ディメンション) を再読み込みする必要がある場合はいつでも、更新中に割り当てられた SK によって、ファクトに保存されている元の値と SK が同期しなくなります。それに結合するすべてのファクト テーブルの完全なリロード。SK が意味のない数字だったとしても、元のレコードや古いレコードでは変更できない方法があるといいのですが。多くの人が知っているように、すぐに使用できるものでは組織のニーズを満たすことはめったになく、常にカスタマイズする必要があります。現在、倉庫には 3 年分のデータがあり、また、Oracle Financial システムからの完全なリロードは非常に大きくなります。したがって、私の場合、それらはデータ入力から生成されるのではなく、レポートのパフォーマンスを向上させるためにウェアハウスに追加されます。わかりますが、私たちのものは変わります。それは悪夢です。