ここで再び行きます、古い議論はまだ起こります...
ビジネスキーを主キーとして使用した方がよいでしょうか、それとも、ビジネスキーフィールドに一意の制約がある代理ID(つまり、SQL Server ID)を使用した方がよいでしょうか。
理論を裏付ける例や証拠を提示してください。
ここで再び行きます、古い議論はまだ起こります...
ビジネスキーを主キーとして使用した方がよいでしょうか、それとも、ビジネスキーフィールドに一意の制約がある代理ID(つまり、SQL Server ID)を使用した方がよいでしょうか。
理論を裏付ける例や証拠を提示してください。
回答:
両方とも。ケーキを持って食べなさい。
そのようにラベル付けされていることを除いて、主キーについて特別なことは何もないことに注意してください。これは、NOT NULL UNIQUE制約に過ぎず、テーブルには複数の制約を設定できます。
代理キーを使用する場合でも、ビジネスルールに従って一意性を確保するビジネスキーが必要です。
代理キーを使用するいくつかの理由:
安定性:ビジネスまたは自然なニーズのためにキーを変更すると、関連するテーブルに悪影響を及ぼします。値に関連付けられている意味がないため、代理キーを変更する必要はほとんどありません。
規則: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などのテーブルには無意味な数値キーを使用しますが、すべての目的には使用できません。これは、なぜかほとんどの人が主張しているようです。
参照:別の質問に対する私の回答
サロゲートキー(通常は整数)は、テーブルの関係を高速化し、ストレージと更新速度をより経済的にするという付加価値があります(ビジネスキーフィールドとは対照的に、サロゲートキーを使用する場合、外部キーを更新する必要はありません)。それは時々変わります)。
テーブルの主キーは、主に結合の目的で、行を一意に識別するために使用する必要があります。Personsテーブルを考えてください。名前は変更される可能性があり、一意であるとは限りません。
企業を考える:あなたはメルキアの他の企業とビジネスをしている幸せなマーキン企業です。会社名を主キーとして使用しない方が賢明なので、10文字の英数字全体でMerkiaの政府の一意の会社IDを使用します。その後、Merkiaは企業IDを変更することをお勧めします。それは大丈夫です、そもそもあなたが関与してはならない変更のために、dbエンジンのカスケード更新機能を使用します。その後、あなたのビジネスは拡大し、今ではフリードニアの会社と仕事をしています。Freedonianの会社IDは最大16文字です。会社IDの主キー(Orders、Issue、MoneyTransfersなどの外部キーフィールドも)を拡大し、主キー(外部キーも)にCountryフィールドを追加する必要があります。痛い!フリードニアでの内戦、それは 3つの国に分かれています。従業員の国名を新しい国名に変更する必要があります。レスキューへのカスケード更新。ところで、あなたの主キーは何ですか?(Country、CompanyID)または(CompanyID、Country)?後者は結合に役立ち、前者は別のインデックスを回避します(注文を国ごとにグループ化したい場合は、おそらく多くのインデックスも回避します)。
これらはすべて証明ではありませんが、結合操作を含むすべての用途で行を一意に識別する代理キーがビジネスキーよりも望ましいことを示しています。
代理キーは一般的に嫌いです。高品質のナチュラルキーがない場合にのみ使用してください。考えてみると、テーブルに無意味なデータを追加することで状況が改善されると考えるのは不合理です。
ここに私の理由があります:
自然キーを使用する場合、テーブルは最も頻繁に検索される方法でクラスター化されるため、クエリが高速になります。
代理キーを使用する場合は、論理キー列に一意のインデックスを追加する必要があります。論理的な重複データを防ぐ必要があります。たとえば、pkがサロゲートID列であっても、組織テーブルで同じ名前の2つの組織を許可することはできません。
代理キーが主キーとして使用される場合、自然な主キーが何であるかははるかに明確ではありません。開発するとき、どの列のセットがテーブルを一意にするかを知りたいです。
1対多の関係チェーンで、論理キーチェーン。したがって、たとえば、組織には多くのアカウントがあり、アカウントには多くの請求書があります。したがって、Organizationの論理キーはOrgNameです。Accountsの論理キーはOrgName、AccountIDです。Invoiceの論理キーは、OrgName、AccountID、InvoiceNumberです。
サロゲートキーが使用される場合、キーチェーンは、直接の親に対する外部キーのみを持つことで切り捨てられます。たとえば、InvoiceテーブルにはOrgName列がありません。AccountIDの列のみがあります。特定の組織の請求書を検索する場合は、組織、アカウント、および請求書テーブルに参加する必要があります。論理キーを使用する場合、組織テーブルを直接クエリできます。
ルックアップテーブルのサロゲートキー値を格納すると、テーブルが無意味な整数で埋められます。データを表示するには、すべてのルックアップテーブルに結合する複雑なビューを作成する必要があります。ルックアップテーブルは、列の許容値のセットを保持するためのものです。代わりに整数の代理キーを格納することで体系化すべきではありません。正規化ルールには、値自体ではなくサロゲート整数を格納する必要があることを示唆するものはありません。
私は3つの異なるデータベースブックを持っています。それらのいずれも代理キーの使用を示していません。
私はこの無限の戦争についてのあなたと私の経験を共有したいと思います:自然対代理の主要なジレンマ。代理キー(人工的に自動生成されたもの)と自然キー(ドメインの意味を持つ列で構成されたもの)の両方に長所と短所があると思います。したがって、状況によっては、どちらか一方の方法を選択する方が適切な場合があります。
多くの人々が代理キーをほぼ完璧な解決策として提示し、自然キーをペストとして提示するように思われるので、私は別の見方の議論に焦点を合わせます。
代理キーは次のとおりです。
必要に応じて自然キーを使用し、適切な場合は代理キーを使用します。
これが誰かを助けたことを願っています!
常にビジネス上の意味がないキーを使用してください。それはただ良い習慣です。
編集:私はそれへのリンクをオンラインで見つけようとしましたが、できませんでした。ただし、「エンタープライズアーキテクチャのパターン」 [ファウラー]では、キー以外の意味を持たないキー以外の何も使用してはならない理由を説明しています。つまり、1つのジョブと1つのジョブのみが必要であるということです。
ORMツールを使用してデータクラスを処理/生成する場合は、代理キーが非常に便利です。より高度なマッパー(読み取り:hibernate)の一部で複合キーを使用できますが、コードが多少複雑になります。
(もちろん、データベースの純粋主義者たちは、代理キーの概念でさえ嫌いだと主張します。)
私は適切なときに代理キーにuidを使用するのが好きです。それらの主な利点は、事前にキーを知っていることです。たとえば、IDが既に設定され、一意であることが保証されているクラスのインスタンスを作成できますが、たとえば、整数キーでは、デフォルトで0または-に設定する必要があります。 1、保存/更新時に適切な値に更新します。
UIDは検索と結合の速度の点で不利ですが、それが望ましいかどうかは、問題のアプリケーションによって異なります。
サロゲートキーを使用する方が、変更される可能性がほとんどないため、私の意見ではより適切です。あなたが自然なキーとして使用する可能性があると私が考えることができるほとんどすべてが変わる可能性があります(免責事項:常に真であるとは限らないが、一般的に)。
一例として、車のDBがあります。一見すると、ナンバープレートをキーとして使用できると思うかもしれません。しかし、これらは変更される可能性があるため、悪い考えです。アプリのリリース後、誰かがあなたのナンバープレートを光沢のある新しいパーソナライズされたものに変更できない理由を知りたくなったときに、それを実際に知りたいとは思わないでしょう。
languages
、言語コード(ID)がすでにテーブルにあるため、テーブルに参加する必要はありませんtexts
。
代理キーは、ビジネス情報が変更または同一になる可能性がある場合に役立ちます。結局のところ、ビジネス名は国全体で一意である必要はありません。たとえば、カンザス州とミシガン州にあるスミスエレクトロニクスという2つの企業を扱っているとします。住所で区別できますが、状況は変わります。状態さえ変化することができます。カンザス州カンザスシティのスミスエレクトロニクスが川を越えてミズーリ州カンザスシティに移動した場合はどうなりますか?これらのビジネスを自然なキー情報で明確に区別する明確な方法はないため、代理キーは非常に役立ちます。
ISBN番号のような代理キーと考えてください。通常、本はタイトルと著者で識別します。しかし、HPウィルモットによる「パールハーバー」というタイトルの本が2冊あり、それらは異なるエディションだけでなく、明らかに異なるブックです。そのような場合、私は本の外見を参照することもできますし、以前のものと後のものを参照することもできますが、ISBNに頼るのも同様です。
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番目の場合:
コース用の馬。私の偏見を述べるために; 私は最初に開発者なので、主にユーザーに実用的なアプリケーションを提供することに関心があります。
私は自然キーを使用するシステムで作業しており、値の変更が波及することを確認するために多くの時間を費やす必要がありました。
私は代理キーのみのシステムで作業してきましたが、唯一の欠点は、パーティション化のための非正規化されたデータがないことです。
ジョインごとのテーブル数が多いため、私が一緒に働いてきたほとんどの従来のPL / SQL開発者は代理キーを好みませんでしたが、テストデータベースと本番データベースでは汗を流しませんでした。追加の結合はアプリケーションのパフォーマンスに影響を与えませんでした。「Xa = YbのX内部結合Y」のような句をサポートしないデータベースの方言、またはその構文を使用しない開発者では、代理キーの追加の結合により、クエリが読みにくくなり、入力や入力が長くなります。チェック:@Tony Andrewsの投稿を参照してください。しかし、ORMまたはその他のSQL生成フレームワークを使用している場合は、それに気付かないでしょう。タッチタイピングも軽減されます。
たぶんこのトピックに完全に関連しているわけではありませんが、代理キーを扱っている頭痛の種です。Oracleの事前提供分析では、ウェアハウス内のすべてのディメンションテーブルに自動生成された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になります。