web-dev-qa-db-ja.com

代理キーと自然/ビジネスキー

ここで再び行きます、古い議論はまだ起こります...

主キーとしてビジネスキーを使用する方が良いでしょうか、またはビジネスキーフィールドに一意の制約を持つ代理ID(つまり、SQL Server ID)を使用する方が良いでしょうか?

理論をサポートするための例または証拠を提供してください。

163
Manrico Corazzi

両方。ケーキを持って食べてください。

主キーについて特別なものはないことを覚えておいてください。これはNOT NULL UNIQUE制約に過ぎず、テーブルには複数の制約を設定できます。

代理キーを使用する場合、ビジネスルールに従って一意性を確保するビジネスキーが必要です。

91
Ted

代理キーを使用する理由はいくつかあります。

  1. 安定性:ビジネスまたは自然なニーズのためにキーを変更すると、関連するテーブルに悪影響を及ぼします。値に関連付けられた意味がないため、代理キーを変更する必要はほとんどありません。

  2. Convention:PKのさまざまな名前を持つテーブルを結合する方法を考える必要なく、標準化された主キー列の命名規則を使用できます。

  3. 速度:PKの値とタイプに応じて、整数の代理キーは小さくなり、インデックス付けと検索が高速になります。

113
Jay Shepherd

非サロゲート(私は「自然」と言うのをためらう)キーをサポートするためにまだ誰も何も言っていないようです。だからここに行く...

代理キーの短所は、それらが意味のない(いくつかの利点がありますが...)。これにより、実際に必要な数よりも多くのテーブルをクエリに結合しなければならないことがあります。比較する:

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には使用しません。

参照: 別の質問への回答

67
Tony Andrews

代理キーには、変更する理由はありません。自然な鍵についても同じことは言えません。姓、メール、ISBN番号-それらはすべて、いつか変わる可能性があります。

29
Rimantas

サロゲートキー(通常は整数)には、テーブルリレーションを高速化し、ストレージと更新速度をより経済的にするという付加価値があります(さらに良いことに、サロゲートキーを使用する場合、ビジネスキーフィールドとは対照的に、外部キーを更新する必要はありませんが、それは時々変わります)。

テーブルの主キーは、主に結合の目的で、行を一意に識別するために使用する必要があります。 Personsテーブルを考えてみましょう。名前は変更できますが、一意であるとは限りません。

企業を考える:Merkiaの他の企業とビジネスを行う幸せなMerkin企業です。会社名を主キーとして使用しないほど賢いので、10個の英数字全体でMerkiaの政府の一意の会社IDを使用します。その後、Merkiaは会社のIDを変更します。なぜなら、彼らはそれが良いアイデアだと思ったからです。そもそもあなたに関係してはならない変更のために、dbエンジンのカスケード更新機能を使用します。その後、ビジネスが拡大し、今ではフリードニアの会社で働いています。 Freedonian会社IDは最大16文字です。会社IDの主キー(Orders、Issues、MoneyTransfersなどの外部キーフィールドも)を拡大し、主キー(および外部キー)にCountryフィールドを追加する必要があります。痛い!フリードニアの内戦、それは3つの国に分かれています。同僚の国名を新しい国名に変更する必要があります。レスキューへのカスケード更新。ところで、あなたの主なキーは何ですか? (国、CompanyID)または(CompanyID、Country)?後者は結合に役立ち、前者は別のインデックスを回避します(国ごとに注文をグループ化する場合は、多くの場合、多数)。

これらはすべて証明ではありませんが、ビジネスキーよりも、結合操作を含むすべての用途の行を一意に識別する代理キーが望ましいことを示しています。

29
tzot

私は一般的に代理キーが嫌いです。使用できる品質の自然キーがない場合にのみ使用してください。考えてみると、意味のないデータをテーブルに追加すると物事が良くなると考えるのはかなりばかげています。

私の理由は次のとおりです。

  1. 自然キーを使用する場合、テーブルは最も頻繁に検索されるようにクラスター化されるため、クエリが高速になります。

  2. 代理キーを使用する場合、論理キー列に一意のインデックスを追加する必要があります。論理的な重複データを防ぐ必要があります。たとえば、pkが代理ID列であっても、Organizationテーブルで同じ名前の2つのOrganizationを許可することはできません。

  3. 代理キーが主キーとして使用される場合、自然な主キーが何であるかはあまり明確ではありません。開発するとき、どの列のセットがテーブルを一意にするかを知りたいです。

  4. 1対多の関係チェーンで、論理キーチェーン。たとえば、組織には多くのアカウントがあり、アカウントには多くの請求書があります。したがって、Organizationの論理キーはOrgNameです。アカウントの論理キーは、OrgName、AccountIDです。 Invoiceの論理キーは、OrgName、AccountID、InvoiceNumberです。

    代理キーが使用される場合、キーチェーンは、直接の親に対する外部キーのみを持つことで切り捨てられます。たとえば、InvoiceテーブルにはOrgName列がありません。 AccountIDの列のみがあります。特定の組織の請求書を検索する場合は、組織、アカウント、および請求書の表に参加する必要があります。論理キーを使用する場合、組織テーブルを直接クエリできます。

  5. ルックアップテーブルの代理キー値を保存すると、テーブルに意味のない整数が入力されます。データを表示するには、すべてのルックアップテーブルに結合する複雑なビューを作成する必要があります。ルックアップテーブルは、列の許容値のセットを保持するためのものです。代わりに整数の代理キーを保存してコード化するべきではありません。値自体の代わりに代理整数を格納する必要があることを示唆する正規化ルールには何もありません。

  6. 3種類のデータベースブックがあります。そのうちの1つは、代理キーの使用を示していません。

26
Ken

この無限の戦争についての私の経験をあなたと共有したいと思います:自然対代理の主要なジレンマ。私はboth代理キー(自動生成された人工キー)と自然キー(ドメインの意味を持つ列で構成されている)はprosおよびconsそのため、状況に応じて、どちらかの方法を選択する方が適切な場合があります。

多くの人が代理キーをほぼ完璧なソリューションとして提示し、自然キーをペストとして提示しているように見えるので、他の観点からの議論に焦点を当てます。

代理キーの欠点

代理キーは次のとおりです。

  1. パフォーマンスの問題の原因:
    • それらは通常、次の意味を持つ自動インクリメント列を使用して実装されます。
      • 新しいIDを取得するたびにデータベースへの往復(キャッシュまたは[seq] hiloアルゴリズムを使用してこれを改善できることは知っていますが、これらのメソッドには独自の欠点があります)。
      • ある日、あるスキーマから別のスキーマにデータを移動する必要がある場合(少なくとも私の会社ではかなり定期的に発生します)、ID衝突の問題が発生する可能性があります。そして、はい、UUIDを使用できることは知っていますが、それらを使用するには32桁の16進数が必要です! (データベースのサイズが気になる場合は、問題になる可能性があります)。
      • すべてのサロゲートキーに1つのシーケンスを使用している場合、確かに、データベースで競合が発生します。
  2. エラーを起こしやすい。シーケンスにはmax_valueの制限があるため、開発者は次の点に注意する必要があります。
    • シーケンスを循環させる必要があります(最大値に達すると、1,2、...に戻ります)。
    • データの順序付けとしてシーケンスを使用している場合(時間の経過とともに)、サイクリングのケースを処理する必要があります(Id 1の列はId max-value-1の行よりも新しい場合があります)。
    • コード(および内部Idであると想定されるべきではないクライアントインターフェイス)が、シーケンス値の格納に使用した32b/64b整数をサポートしていることを確認してください。
  3. 重複していないデータを保証するものではありません。すべての列値は同じであるが生成値が異なる2つの行を常に持つことができます。私にとってこれは、[〜#〜] [〜#〜]データベース設計の観点からの代理キーの問題です。
  4. Wikipediaの詳細...

自然キーの神話

  1. 複合キーは、代理キーよりも非効率的です。番号!使用するデータベースエンジンによって異なります。
  2. 自然キーは実生活には存在しません。申し訳ありませんが、存在します!たとえば、航空業界では、次のTupleは、指定されたスケジュールフライト(airline、departmentDate、flightNumber、operationalSuffix)に関して常に一意です。より一般的には、ビジネスデータのセットが特定のstandardによって一意であることが保証されている場合、このデータのセットは[良い]自然キー候補です。
  3. 自然キーは、子テーブルの「スキーマを汚染する」。私にとって、これは本当の問題というよりも感覚です。それぞれ2バイトの4列の主キーを持つことは、11バイトの単一列よりも効率的です。また、4つの列を使用して、親テーブルに結合せずに(where句で4つの列を使用して)子テーブルを直接クエリできます。

結論

必要に応じて自然キーを使用し、使用する方が適切な場合は代理キーを使用します。

これが誰かを助けたことを願っています!

17
mwnsiri

常にビジネス上の意味のないキーを使用します。それはちょうど良い習慣です。

編集:私はそれへのリンクをオンラインで見つけようとしていましたが、見つけることができませんでした。ただし、 'Patterns of Enterprise Archtecture' [Fowler]では、キー以外の意味を持たないキー以外のものを使用しない理由を説明しています。つまり、1つのジョブと1つのジョブのみを持つ必要があるという事実に要約されます。

15
Iain Holder

ORMツールを使用してデータクラスを処理/生成する場合、代理キーは非常に便利です。いくつかのより高度なマッパーで複合キーを使用できますが(読み取り:休止状態)、コードに複雑さが追加されます。

(もちろん、データベースの純粋主義者は、代理キーの概念でさえ憎悪であると主張するでしょう。)

適切な場合、代理キーにuidを使用するのが好きです。それらの主な利点は、事前にキーを知っていることです。既に設定され、一意であることが保証されているIDを持つクラスのインスタンスを作成できます。一方、整数キーでは、デフォルトで0または-1に設定し、保存/更新時に適切な値に更新する必要があります。

UIDにはルックアップと結合速度の点でペナルティがありますが、UIDが望ましいかどうかは問題のアプリケーションに依存します。

9
Derek Lawless

代理キーを使用することは、変更される可能性がゼロであるため、私の意見ではより優れています。あなたが自然なキーとして使用するかもしれないと思うものはほとんど変化する可能性があります(免責事項:常に真実ではありませんが、一般的に)。

例としては車のDBがあります-一見すると、ナンバープレートがキーとして使用できると思うかもしれません。しかし、これらは変更される可能性があるので、それは悪い考えです。誰かがナンバープレートを光沢のある新しいパーソナライズされたものに変更できない理由を知りたいと思ってあなたに来たとき、あなたは本当にそれを見つけたくないでしょうafter.

6
Mark Embling

可能な限り、常に単一の列、代理キーを使用してください。単一の情報を追跡して記録を維持するだけなので、結合と挿入/更新/削除がよりきれいになります。

次に、必要に応じて、ビジネスキーを一意の制約またはインデックスとしてスタックします。これにより、データの整合性が維持されます。

ビジネスロジック/自然キーは変更できますが、テーブルの物理キーは変更しないでください。

5
user7658

データウェアハウスのシナリオでは、代理キーパスに従う方が良いと考えています。 2つの理由:

  • あなたはソースシステムから独立しており、そこでの変更(データ型の変更など)は影響しません。
  • 代理キーには整数データ型のみを使用するため、DWで必要な物理スペースは少なくなります。また、インデックスの機能も向上します。
4
Santiago Cepas

これは、代理キーがほとんどalwaysを意味する場合の1つです。データベースに最適なもの、またはオブジェクトモデルに最適なものを選択する場合がありますが、どちらの場合も、意味のないキーまたはGUIDを使用する方が良いアイデアです。より速く、変更されないのはオブジェクトのIDです。

2
Charles Graham

SQL Serverにはこれらのデータを物理的に並べ替える能力がないため、クラスター化インデックスをランダムな代理キー、つまりXY8D7-DFD8Sを読み取るGUIDに配置することはお勧めできません。代わりに、これらのデータに一意のインデックスを配置する必要がありますが、メインテーブル操作に対してSQLプロファイラーを実行してから、それらのデータをデータベースエンジンチューニングアドバイザーに配置することも有益です。

スレッド@を参照してください http://social.msdn.Microsoft.com/Forums/en-us/sqlgetstarted/thread/27bd9c77-ec31-44f1-ab7f-bd2cb13129be

2
Bryan Swan

ケース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)

最初の場合:

  • テーブルJOBとの結合を使用せずに、テーブルPEOPLE内のすべてのプログラマーを選択できますが、「SELECT * FROM PEOPLE WHERE JOBCODE = 'PRG'」のみを使用できます。

2番目の場合:

  • 主キーが整数であるため、データベースクエリが高速になります。
  • データベース自体が次の自動インクリメントを提供するため、次の一意のキーを見つけることに煩わされる必要はありません。
2
Stefanos Kargas

サロゲートキーは、ビジネス情報が変更される場合や同一になる場合に役立ちます。結局のところ、会社名は全国で一意である必要はありません。カンザス州とミシガン州にあるスミスエレクトロニクスという2つのビジネスを扱っているとします。アドレスで区別できますが、変更されます。状態さえも変化する可能性があります。カンザス州カンザスシティのスミスエレクトロニクスが川を渡ってミズーリ州カンザスシティに移動するとどうなりますか?これらのビジネスを自然なキー情報で区別する明確な方法はないため、代理キーは非常に便利です。

代理キーはISBN番号のように考えてください。通常、書籍はタイトルと著者で識別します。しかし、H。P.ウィルモットによる「パールハーバー」というタイトルの本が2冊ありますが、それらは異なる版ではなく、間違いなく異なる本です。そのような場合、私は本の見た目、または早いものと遅いものを参照することができますが、ISBNが当てはまるのは同じことです。

2
David Thornley

コース用の馬。私のバイアスを述べるために;私は最初に開発者なので、主にユーザーに機能するアプリケーションを提供することに関心があります。

私は自然なキーを持つシステムに取り組んでおり、値の変更が波及することを確認するために多くの時間を費やさなければなりませんでした。

サロゲートキーのみを使用するシステムに取り組んできましたが、唯一の欠点は、パーティション分割のための非正規化データの不足でした。

私がこれまで働いてきたほとんどの従来のPL/SQL開発者は、結合ごとのテーブルの数が多いため、代理キーが好きではありませんでしたが、テストデータベースと運用データベースは汗をかきませんでした。追加の結合はアプリケーションのパフォーマンスに影響しませんでした。 「Xa = YbのX内部結合Y」などの句をサポートしないデータベース方言、またはその構文を使用しない開発者の場合、サロゲートキーの余分な結合により、クエリが読みにくくなり、入力と入力が長くなりますチェック:@Tony Andrewsの投稿を参照してください。しかし、ORMまたはその他のSQL生成フレームワークを使用している場合、それに気付くことはありません。タッチタイピングも軽減します。

1
WillC

このトピックに完全に関連しているわけではないかもしれませんが、サロゲートキーを扱っている頭痛の種です。オラクルの事前配信アナリティクスは、ウェアハウス内のすべてのディメンション表で自動生成されたSKを作成し、ファクトにも保存します。そのため、新しい列が追加されたり、ディメンション内のすべてのアイテムにデータを設定する必要があるため、それらの(ディメンション)を再ロードする必要があるたびに、更新中に割り当てられたSKは、SKをファクトに保存されている元の値と同期しなくなります結合するすべてのファクトテーブルの完全な再読み込み。 SKが無意味な数字であったとしても、元のレコードや古いレコードでは変更できない何らかの方法があると思います。多くの人が知っているように、箱から出してすぐに組織のニーズを満たすことはめったになく、私たちは常にカスタマイズする必要があります。現在、ウェアハウスには3年間分のデータがあり、Oracle Financialシステムからの完全なリロードは非常に大きくなっています。したがって、私の場合、それらはデータ入力から生成されるのではなく、パフォーマンスをレポートするためにウェアハウスに追加されます。わかりましたが、私たちのものは変わり、それは悪夢です。

1
lrb

特定時点のデータベースの場合、代理キーと自然キーの組み合わせを使用するのが最適です。例えばクラブの会員情報を追跡する必要があります。メンバーの一部の属性は変更されません。例:生年月日ですが、名前は変更できます。したがって、member_id代理キーを使用してMemberテーブルを作成し、DOBの列を作成します。 person nameという別のテーブルを作成し、member_id、member_fname、member_lname、date_updatedの列を作成します。このテーブルでは、自然キーはmember_id + date_updatedになります。

0
kanad