ここで再び行きます、古い議論はまだ起こります...
主キーとしてビジネスキーを使用する方が良いでしょうか、またはビジネスキーフィールドに一意の制約を持つ代理ID(つまり、SQL Server ID)を使用する方が良いでしょうか?
理論をサポートするための例または証拠を提供してください。
両方。ケーキを持って食べてください。
主キーについて特別なものはないことを覚えておいてください。これはNOT NULL UNIQUE制約に過ぎず、テーブルには複数の制約を設定できます。
代理キーを使用する場合、ビジネスルールに従って一意性を確保するビジネスキーが必要です。
代理キーを使用する理由はいくつかあります。
安定性:ビジネスまたは自然なニーズのためにキーを変更すると、関連するテーブルに悪影響を及ぼします。値に関連付けられた意味がないため、代理キーを変更する必要はほとんどありません。
Convention:PKのさまざまな名前を持つテーブルを結合する方法を考える必要なく、標準化された主キー列の命名規則を使用できます。
速度:PKの値とタイプに応じて、整数の代理キーは小さくなり、インデックス付けと検索が高速になります。
非サロゲート(私は「自然」と言うのをためらう)キーをサポートするためにまだ誰も何も言っていないようです。だからここに行く...
代理キーの短所は、それらが意味のない(いくつかの利点がありますが...)。これにより、実際に必要な数よりも多くのテーブルをクエリに結合しなければならないことがあります。比較する:
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などのテーブルには無意味な数値キーを使用しますが、everythingには使用しません。
参照: 別の質問への回答
代理キーには、変更する理由はありません。自然な鍵についても同じことは言えません。姓、メール、ISBN番号-それらはすべて、いつか変わる可能性があります。
サロゲートキー(通常は整数)には、テーブルリレーションを高速化し、ストレージと更新速度をより経済的にするという付加価値があります(さらに良いことに、サロゲートキーを使用する場合、ビジネスキーフィールドとは対照的に、外部キーを更新する必要はありませんが、それは時々変わります)。
テーブルの主キーは、主に結合の目的で、行を一意に識別するために使用する必要があります。 Personsテーブルを考えてみましょう。名前は変更できますが、一意であるとは限りません。
企業を考える:Merkiaの他の企業とビジネスを行う幸せなMerkin企業です。会社名を主キーとして使用しないほど賢いので、10個の英数字全体でMerkiaの政府の一意の会社IDを使用します。その後、Merkiaは会社のIDを変更します。なぜなら、彼らはそれが良いアイデアだと思ったからです。そもそもあなたに関係してはならない変更のために、dbエンジンのカスケード更新機能を使用します。その後、ビジネスが拡大し、今ではフリードニアの会社で働いています。 Freedonian会社IDは最大16文字です。会社IDの主キー(Orders、Issues、MoneyTransfersなどの外部キーフィールドも)を拡大し、主キー(および外部キー)にCountryフィールドを追加する必要があります。痛い!フリードニアの内戦、それは3つの国に分かれています。同僚の国名を新しい国名に変更する必要があります。レスキューへのカスケード更新。ところで、あなたの主なキーは何ですか? (国、CompanyID)または(CompanyID、Country)?後者は結合に役立ち、前者は別のインデックスを回避します(国ごとに注文をグループ化する場合は、多くの場合、多数)。
これらはすべて証明ではありませんが、ビジネスキーよりも、結合操作を含むすべての用途の行を一意に識別する代理キーが望ましいことを示しています。
私は一般的に代理キーが嫌いです。使用できる品質の自然キーがない場合にのみ使用してください。考えてみると、意味のないデータをテーブルに追加すると物事が良くなると考えるのはかなりばかげています。
私の理由は次のとおりです。
自然キーを使用する場合、テーブルは最も頻繁に検索されるようにクラスター化されるため、クエリが高速になります。
代理キーを使用する場合、論理キー列に一意のインデックスを追加する必要があります。論理的な重複データを防ぐ必要があります。たとえば、pkが代理ID列であっても、Organizationテーブルで同じ名前の2つのOrganizationを許可することはできません。
代理キーが主キーとして使用される場合、自然な主キーが何であるかはあまり明確ではありません。開発するとき、どの列のセットがテーブルを一意にするかを知りたいです。
1対多の関係チェーンで、論理キーチェーン。たとえば、組織には多くのアカウントがあり、アカウントには多くの請求書があります。したがって、Organizationの論理キーはOrgNameです。アカウントの論理キーは、OrgName、AccountIDです。 Invoiceの論理キーは、OrgName、AccountID、InvoiceNumberです。
代理キーが使用される場合、キーチェーンは、直接の親に対する外部キーのみを持つことで切り捨てられます。たとえば、InvoiceテーブルにはOrgName列がありません。 AccountIDの列のみがあります。特定の組織の請求書を検索する場合は、組織、アカウント、および請求書の表に参加する必要があります。論理キーを使用する場合、組織テーブルを直接クエリできます。
ルックアップテーブルの代理キー値を保存すると、テーブルに意味のない整数が入力されます。データを表示するには、すべてのルックアップテーブルに結合する複雑なビューを作成する必要があります。ルックアップテーブルは、列の許容値のセットを保持するためのものです。代わりに整数の代理キーを保存してコード化するべきではありません。値自体の代わりに代理整数を格納する必要があることを示唆する正規化ルールには何もありません。
3種類のデータベースブックがあります。そのうちの1つは、代理キーの使用を示していません。
この無限の戦争についての私の経験をあなたと共有したいと思います:自然対代理の主要なジレンマ。私はboth代理キー(自動生成された人工キー)と自然キー(ドメインの意味を持つ列で構成されている)はprosおよびconsそのため、状況に応じて、どちらかの方法を選択する方が適切な場合があります。
多くの人が代理キーをほぼ完璧なソリューションとして提示し、自然キーをペストとして提示しているように見えるので、他の観点からの議論に焦点を当てます。
代理キーは次のとおりです。
必要に応じて自然キーを使用し、使用する方が適切な場合は代理キーを使用します。
これが誰かを助けたことを願っています!
常にビジネス上の意味のないキーを使用します。それはちょうど良い習慣です。
編集:私はそれへのリンクをオンラインで見つけようとしていましたが、見つけることができませんでした。ただし、 'Patterns of Enterprise Archtecture' [Fowler]では、キー以外の意味を持たないキー以外のものを使用しない理由を説明しています。つまり、1つのジョブと1つのジョブのみを持つ必要があるという事実に要約されます。
ORMツールを使用してデータクラスを処理/生成する場合、代理キーは非常に便利です。いくつかのより高度なマッパーで複合キーを使用できますが(読み取り:休止状態)、コードに複雑さが追加されます。
(もちろん、データベースの純粋主義者は、代理キーの概念でさえ憎悪であると主張するでしょう。)
適切な場合、代理キーにuidを使用するのが好きです。それらの主な利点は、事前にキーを知っていることです。既に設定され、一意であることが保証されているIDを持つクラスのインスタンスを作成できます。一方、整数キーでは、デフォルトで0または-1に設定し、保存/更新時に適切な値に更新する必要があります。
UIDにはルックアップと結合速度の点でペナルティがありますが、UIDが望ましいかどうかは問題のアプリケーションに依存します。
代理キーを使用することは、変更される可能性がゼロであるため、私の意見ではより優れています。あなたが自然なキーとして使用するかもしれないと思うものはほとんど変化する可能性があります(免責事項:常に真実ではありませんが、一般的に)。
例としては車のDBがあります-一見すると、ナンバープレートがキーとして使用できると思うかもしれません。しかし、これらは変更される可能性があるので、それは悪い考えです。誰かがナンバープレートを光沢のある新しいパーソナライズされたものに変更できない理由を知りたいと思ってあなたに来たとき、あなたは本当にそれを見つけたくないでしょうafter.
可能な限り、常に単一の列、代理キーを使用してください。単一の情報を追跡して記録を維持するだけなので、結合と挿入/更新/削除がよりきれいになります。
次に、必要に応じて、ビジネスキーを一意の制約またはインデックスとしてスタックします。これにより、データの整合性が維持されます。
ビジネスロジック/自然キーは変更できますが、テーブルの物理キーは変更しないでください。
データウェアハウスのシナリオでは、代理キーパスに従う方が良いと考えています。 2つの理由:
これは、代理キーがほとんどalwaysを意味する場合の1つです。データベースに最適なもの、またはオブジェクトモデルに最適なものを選択する場合がありますが、どちらの場合も、意味のないキーまたはGUIDを使用する方が良いアイデアです。より速く、変更されないのはオブジェクトのIDです。
SQL Serverにはこれらのデータを物理的に並べ替える能力がないため、クラスター化インデックスをランダムな代理キー、つまりXY8D7-DFD8Sを読み取るGUIDに配置することはお勧めできません。代わりに、これらのデータに一意のインデックスを配置する必要がありますが、メインテーブル操作に対してSQLプロファイラーを実行してから、それらのデータをデータベースエンジンチューニングアドバイザーに配置することも有益です。
スレッド@を参照してください http://social.msdn.Microsoft.com/Forums/en-us/sqlgetstarted/thread/27bd9c77-ec31-44f1-ab7f-bd2cb13129be
ケース1:あなたのテーブルはルックアップテーブル 50種類未満(挿入)
ビジネス/ナチュラルキーを使用します。例えば:
Table: JOB with 50 inserts
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
ケース2:あなたのテーブルは挿入数千のテーブル
代理/自動インクリメントキーを使用します。例えば:
Table: ASSIGNMENT with 1000000 inserts
joined with
Table: PEOPLE with 100000 inserts
foreign key PEOPLEID in table ASSIGNMENT
looks at
primary key ID in table PEOPLE (autoincrement)
最初の場合:
2番目の場合:
サロゲートキーは、ビジネス情報が変更される場合や同一になる場合に役立ちます。結局のところ、会社名は全国で一意である必要はありません。カンザス州とミシガン州にあるスミスエレクトロニクスという2つのビジネスを扱っているとします。アドレスで区別できますが、変更されます。状態さえも変化する可能性があります。カンザス州カンザスシティのスミスエレクトロニクスが川を渡ってミズーリ州カンザスシティに移動するとどうなりますか?これらのビジネスを自然なキー情報で区別する明確な方法はないため、代理キーは非常に便利です。
代理キーはISBN番号のように考えてください。通常、書籍はタイトルと著者で識別します。しかし、H。P.ウィルモットによる「パールハーバー」というタイトルの本が2冊ありますが、それらは異なる版ではなく、間違いなく異なる本です。そのような場合、私は本の見た目、または早いものと遅いものを参照することができますが、ISBNが当てはまるのは同じことです。
コース用の馬。私のバイアスを述べるために;私は最初に開発者なので、主にユーザーに機能するアプリケーションを提供することに関心があります。
私は自然なキーを持つシステムに取り組んでおり、値の変更が波及することを確認するために多くの時間を費やさなければなりませんでした。
サロゲートキーのみを使用するシステムに取り組んできましたが、唯一の欠点は、パーティション分割のための非正規化データの不足でした。
私がこれまで働いてきたほとんどの従来のPL/SQL開発者は、結合ごとのテーブルの数が多いため、代理キーが好きではありませんでしたが、テストデータベースと運用データベースは汗をかきませんでした。追加の結合はアプリケーションのパフォーマンスに影響しませんでした。 「Xa = YbのX内部結合Y」などの句をサポートしないデータベース方言、またはその構文を使用しない開発者の場合、サロゲートキーの余分な結合により、クエリが読みにくくなり、入力と入力が長くなりますチェック:@Tony Andrewsの投稿を参照してください。しかし、ORMまたはその他のSQL生成フレームワークを使用している場合、それに気付くことはありません。タッチタイピングも軽減します。
このトピックに完全に関連しているわけではないかもしれませんが、サロゲートキーを扱っている頭痛の種です。オラクルの事前配信アナリティクスは、ウェアハウス内のすべてのディメンション表で自動生成されたSKを作成し、ファクトにも保存します。そのため、新しい列が追加されたり、ディメンション内のすべてのアイテムにデータを設定する必要があるため、それらの(ディメンション)を再ロードする必要があるたびに、更新中に割り当てられたSKは、SKをファクトに保存されている元の値と同期しなくなります結合するすべてのファクトテーブルの完全な再読み込み。 SKが無意味な数字であったとしても、元のレコードや古いレコードでは変更できない何らかの方法があると思います。多くの人が知っているように、箱から出してすぐに組織のニーズを満たすことはめったになく、私たちは常にカスタマイズする必要があります。現在、ウェアハウスには3年間分のデータがあり、Oracle Financialシステムからの完全なリロードは非常に大きくなっています。したがって、私の場合、それらはデータ入力から生成されるのではなく、パフォーマンスをレポートするためにウェアハウスに追加されます。わかりましたが、私たちのものは変わり、それは悪夢です。
特定時点のデータベースの場合、代理キーと自然キーの組み合わせを使用するのが最適です。例えばクラブの会員情報を追跡する必要があります。メンバーの一部の属性は変更されません。例:生年月日ですが、名前は変更できます。したがって、member_id代理キーを使用してMemberテーブルを作成し、DOBの列を作成します。 person nameという別のテーブルを作成し、member_id、member_fname、member_lname、date_updatedの列を作成します。このテーブルでは、自然キーはmember_id + date_updatedになります。