web-dev-qa-db-ja.com

複合主キーと一意のオブジェクトIDフィールド

複合キーは一意のオブジェクトIDフィールドを使用するよりもはるかに理想的であり、データベースを作成するときは単一の一意のIDで なし 主キーとして使用されます。 Railsこのデータベースのフロントエンドを作成していたので、Railsの規則に準拠するようにすることが困難でした(カスタムを使用して可能でしたが、ビューと複合キーを処理するためのいくつかの追加の宝石)。

この特定のスキーマ設計の背後にある理由は、データベースのIDフィールドを非効率的な方法で処理する方法と、インデックスの構築時にツリーの並べ替えに欠陥があるためです。この説明には奥行きがありませんでしたが、私はまだコンセプトに頭を抱えています(複合キーの使用に精通していますが、100%の時間ではありません)。

誰かがこのトピックに意見を提供したり、より深いものを追加できますか?

71
mwilliams

一般的に使用されているほとんどのエンジン(MS SQL Server、Oracle、DB2、MySQLなど)では、代理キーシステムを使用しても目立った問題は発生しません。サロゲートの使用によってパフォーマンスが向上する場合もありますが、パフォーマンスの問題はプラットフォーム固有のものです。

一般的に言えば、自然キー(ひいては複合キー)と代理キーの議論には長い歴史があり、「正しい答え」は見当たらないでしょう。

自然キー(単数または複合)の引数には、通常、次のものが含まれます。

1)これらはすでにデータモデルで使用できます。モデル化されているほとんどのエンティティには、リレーションを作成するためのキーのニーズを満たす1つ以上の属性または属性の組み合わせがすでに含まれています。各テーブルに属性を追加すると、不要な冗長性が組み込まれます。

2)これらは特定の結合の必要性を排除します。たとえば、顧客コードを持つ顧客と、請求書番号(どちらも「自然な」キー)を持つ請求書があり、すべてを取得したい場合特定の顧客コードの請求書番号は、単に"SELECT InvoiceNumber FROM Invoice WHERE CustomerCode = 'XYZ123'"を使用できます。従来の代理キーアプローチでは、SQLは"SELECT Invoice.InvoiceNumber FROM Invoice INNER JOIN Customer ON Invoice.CustomerID = Customer.CustomerID WHERE Customer.CustomerCode = 'XYZ123'"のようになります。

3)これらは、データモデリングへのより普遍的な適用可能なアプローチに貢献します。自然キーを使用すると、同じ設計を異なるSQLエンジン間でほとんど変更せずに使用できます。多くの代理キーアプローチでは、キー生成に特定のSQLエンジンテクニックを使用しているため、さまざまなプラットフォームに実装するために、データモデルをさらに特殊化する必要があります。

サロゲートキーの引数は、SQLエンジン固有の問題を中心に展開する傾向があります。

1)ビジネス要件/ルールが変更されたときに属性を簡単に変更できるようにします。これは、データ属性を単一のテーブルに分離できるためです。これは主に、DOMAINなどの標準SQL構造を効率的に実装しないSQLエンジンの問題です。属性がDOMAINステートメントによって定義されている場合、属性に対する変更は、ALTER DOMAINステートメントを使用してスキーマ全体で実行できます。異なるSQLエンジンはドメインを変更するための異なるパフォーマンス特性を持ち、一部のSQLエンジンはDOMAINSをまったく実装しないため、データモデラーは代理キーを追加してこれらの状況を補正し、属性を変更する機能を改善します。

2)自然キーよりも同時実行性の実装が容易になります。自然キーの場合、2人のユーザーが顧客行などの同じ情報セットで同時に作業していて、ユーザーの1人が自然なキー値の場合、更新している顧客コードがデータベースに存在しないため、2番目のユーザーによる更新は失敗します。サロゲートキーの場合、不変のID値は、変更可能な顧客コードではなくデータベースの行を識別するために使用されるため、更新は正常に処理されます。ただし、2番目の更新を許可することが常に望ましいとは限りません。顧客コードが変更された場合、行の実際の「ID」が変更されたため、2番目のユーザーは変更を続行できない場合があります。2番目のユーザーは間違った行を更新している。サロゲートキーもナチュラルキーも、この問題に対処するものではありません。包括的な同時実行ソリューションは、キーの実装以外で対処する必要があります。

3)自然キーよりもパフォーマンスが優れています。パフォーマンスは、SQLエンジンの影響を最も直接受けます。異なるSQLエンジンを使用して同じハードウェアに実装された同じデータベーススキーマは、SQLエンジンのデータストレージと検索メカニズムにより、パフォーマンス特性が劇的に異なることがよくあります。一部のSQLエンジンは、顧客コードなどの同じ属性がデータベーススキーマの複数の場所に出現すると、データが実際に冗長に格納されるフラットファイルシステムに非常に近くなります。 SQLエンジンによるこの冗長ストレージは、データまたはスキーマに変更を加える必要がある場合にパフォーマンスの問題を引き起こす可能性があります。他のSQLエンジンは、データモデルとストレージ/取得システムをより適切に分離し、データとスキーマのより迅速な変更を可能にします。

4)サロゲートキーは、特定のデータアクセスライブラリとGUIフレームワークでより適切に機能します。ほとんどのサロゲートキーデザイン(例:すべてのリレーショナルキーは整数)、データアクセスライブラリ、ORM、およびGUIの均一な性質によるフレームワークは、データの特別な知識を必要とせずに情報を操作できます。自然キーは、異種の性質(異なるデータタイプ、サイズなど)のため、自動または半自動のツールキットとライブラリではうまく機能しません。組み込みSQLデータベースなどの特殊なシナリオでは、特定のツールキットを念頭に置いてデータベースを設計することも可能です。他のシナリオでは、データベースはエンタープライズ情報リソースであり、複数のプラットフォーム、アプリケーション、レポートシステム、およびデバイスによって同時にアクセスされるため、特定のライブラリまたはフレームワークに重点を置いて設計されている場合は機能しません。さらに、特定のツールキットで動作するように設計されたデータベースは、次の優れたツールキットが導入されたときに責任を負います。

私は当然のことながら自然な鍵の側に落ちる傾向がありますが、それについては狂信的ではありません。私が作業している環境のため、設計を支援するデータベースがさまざまなアプリケーションで使用される可能性があるため、大部分のデータモデリングに自然キーを使用し、サロゲートを導入することはほとんどありません。ただし、サロゲートを使用する既存のデータベースを再実装しようとすることはありません。サロゲートキーシステムは問題なく機能します。既に正常に機能しているものを変更する必要はありません。

それぞれのアプローチのメリットを説明する優れたリソースがいくつかあります。

http://www.google.com/search?q=natural+key+surrogate+key

http://www.agiledata.org/essays/keys.html

http://www.informationweek.com/news/software/bi/201806814

88
JeremyDWill

私は15年間データベースアプリケーションを開発してきましたが、サロゲートキーよりも非サロゲートキーの方が良い選択に遭遇したことはありません。

そのようなケースが存在しないと言っているのではなく、実際にデータベースにアクセスするアプリケーションを実際に開発するという実際的な問題を考慮に入れると、通常、代理キーの利点が非-代理キー。

32
Darrel Miller

主キーは定数かつ無意味である必要があります。非代理キーは通常、いずれかまたは両方の要件を満たしていないため、最終的には

  • キーが一定でない場合、非常に複雑になる可能性がある将来の更新の問題があります

  • キーが無意味ではない場合、変更される可能性が高くなります。つまり、一定ではありません。上記を参照

簡単で一般的な例を見てみましょう。在庫アイテムのテーブルです。アイテム番号(SKU番号、バーコード、パーツコードなど)を主キーにしたくなるかもしれませんが、1年後すべてのアイテム番号が変更されますで、乱雑なデータベース全体の更新の問題...

編集:哲学よりも実用的な追加の問題があります。多くの場合、特定の行を何らかの方法で検索し、後でそれを更新するか、再度検索します(またはその両方)。複合キーを使用すると、追跡するデータが増え、WHERE句には再検索または更新(または削除)の制約が増えます。その間、主要なセグメントの1つが変更された可能性もあります。サロゲートキーを使用すると、保持する値(サロゲートID)は常に1つだけであり、定義上は変更できないため、状況が大幅に簡素化されます。

22
Steven A. Lowe

それはsoundsは、データベースを作成した人が、素晴らしい自然キーと代理キーの議論よりも自然キーの側にいるようです。

IDフィールドのbtreeに関する問題については聞いたことがありませんが、それについて深く調べたこともありません...

私は代理キーの側に落ちます:他のテーブルで単一の値を繰り返すだけなので、代理キーを使用するときの繰り返しが少なくなります。人間がテーブルを手で結合することはめったにないので、それが数であるかどうかは気にしません。また、インデックスで検索する固定サイズの列は1つしかないため、サロゲートが主キーによる検索時間も高速であると想定しても安全です。

11
Powerlord

「一意の(オブジェクト)ID」フィールドを使用すると、結合が簡素化されますが、他の(おそらく複合)キーを一意のままにすることを目指してください。nullでない制約を緩和せず、一意の制約を維持してください。

DBMSが一意の整数を効果的に処理できない場合、大きな問題が発生します。ただし、「一意の(オブジェクト)ID」と他のキーの両方を使用すると、他のキーだけよりも(インデックス用に)より多くのスペースが使用され、各挿入操作で更新する2つのインデックスがあります。したがって、それは無料ではありません。ただし、元のキーも保持している限り、問題はありません。他のキーを削除すると、システムの設計が壊れます。すべての地獄は最終的には解けます(そして、あなたは地獄が解けたことに気付くかもしれませんし、しないかもしれません)。

5

私は基本的に代理キーチームのメンバーです。JeremyDWillがここで提示したような議論を高く評価して理解しても、「自然な」キーが代理よりも優れているケースを探しています...

この問題を扱っている他の投稿では、通常、リレーショナルデータベースの理論とデータベースのパフォーマンスについて言及しています。この場合は常に忘れられるもう1つの興味深い議論は、テーブルの正規化およびコードの生産性に関連しています。

テーブルを作成するたびに、時間を失います

  1. 主キーとその物理的特性(タイプ、サイズ)を識別する
  2. コードで参照するたびにこれらの特性を覚えていますか?
  3. チームの他の開発者に私のPKの選択を説明しますか?

私の答えはこれらの質問すべてにノーです:

  1. 人のリストを処理するときに、「最高の主キー」を特定しようとすることに時間を費やす余裕はありません。
  2. "computer"テーブルの主キーが64文字の長さの文字列であることを思い出したくありません(Windowsはコンピューター名にその数の文字を受け入れますか?)。
  3. 他の開発者に自分の選択を説明したくないのですが、そのうちの1人が最終的に「そうですが、異なるドメインでコンピューターを管理する必要があると考えます。この64文字の文字列でドメイン名+コンピュータネーム?"。

したがって、私は過去5年間、非常に基本的なルールで作業してきました。各テーブル( 'myTable'と呼びましょう)には、 'id_MyTable'という最初のフィールドがあり、uniqueIdentifierタイプです。このテーブルが「ComputerUser」テーブルなどの「多対多」リレーションをサポートする場合でも、「id_Computer」と「id_User」の組み合わせは非常に許容できる主キー。ルールに固執するために、この「id_ComputerUser」フィールドをuniqueIdentifierとして作成することを好みます。

主な利点は、コード内での主キーや外部キーの使用について、特に気にする必要がないことです。テーブル名を取得すると、PKの名前とタイプがわかります。データモデルに実装されているリンクがわかると、テーブルで使用できる外部キーの名前がわかります。

私のルールが最高だとは思いません。しかし、それは非常に効率的なものです!

5

新しいアーキテクチャを開発するための実用的なアプローチは、数千のマルチカラムの非常にユニークなレコードを含むテーブルの代理キーと短い説明テーブルの複合キーを利用するものです。私は通常、大学が代理キーの使用を指示しているのに対し、現実のプログラマーは複合キーを好むことに気づきます。あなたは本当に正しいタイプの主キーをテーブルに適用する必要があります-どちらか一方だけではありません。

4
sbeamers

私はここで短くて甘くなります。最近の複合主キーは良くありません。一意の制約を使用して現在のキースキームを維持できる場合は、代理キーを追加します。 ORMは幸せです、あなたは幸せです、元のプログラマーはそれほど幸せではありませんが、彼があなたのボスでなければ、彼はそれに対処することができます。

3
MattC

自然キーを使用すると、永続ORレイヤーとして任意の自動ORMを使用する悪夢になります。また、複数の列の外部キーは互いにオーバーラップする傾向があるため、OOの方法で関係をナビゲートおよび更新するときに、これによりさらに問題が発生します。

それでも、固有の制約で自然キーを変換し、自動生成されたIDを追加できます。これは外部キーの問題を取り除きませんが、それらは手動で変更する必要があります。うまくいけば、複数の列と重なり合う制約がすべての関係の少数派になるので、最も重要な場所でリファクタリングに集中できます。

自然なpkにはモチベーションと使用法のシナリオがあり、悪いことではありません(tm)。ORMとうまく調和しない傾向があるだけです。

他の概念と同様に、自然なキーとテーブルの正規化は、ブラインドデザインの制約としてではなく、賢明なときに使用する必要があると私は感じています。

3

複合キーは良い場合があります-それらはパフォーマンスに影響を与える可能性があります-しかし、唯一の答え(代理)キーが唯一の答えではないのと同じように、それらは唯一の答えではありません。

気になるのは、複合キーを選択する理由の曖昧さです。技術的なことについて漠然とすることはよくありますが、理解が不足していることを示しています。おそらく、本や記事で誰か他の人のガイドラインに従っているのかもしれません。

単一の一意のIDには何の問題もありません。データベースサーバーに接続されているアプリケーションがあり、使用しているデータベースを選択できる場合は、それがすべて適切であり、キーを使用してほとんど何でもできます。それほどひどく苦しむことはありません。

単一の回答がないため、これについては多くのことが書かれています。熟練した方法で慎重に適用する必要がある方法とアプローチがあります。

データベースによってIDが自動的に提供されることで多くの問題が発生しました。可能な限り回避しますが、それでも時折使用します。

2

私は経験豊富ではありませんが、主キーをidとして使用することに賛成です。ここでは例を使用して説明します。

外部データの形式は、時間の経過とともに変化する可能性があります。たとえば、本のISBNは本の表で適切な主キーになると考えるかもしれません。結局のところ、ISBNは一意です。しかし、この特定の本が執筆されているため、米国の出版業界は、すべてのISBNに数字が追加されるにつれて、大きな変化に備えています。 ISBNを本の表の主キーとして使用した場合、この変更を反映するために各行を更新する必要があります。しかし、その後、別の問題が発生します。データベースには、主キーを介してBooksテーブルの行を参照する他のテーブルがあります。これらの参照をすべて最初に確認して更新しない限り、booksテーブルのキーを変更することはできません。これには、外部キー制約の削除、テーブルの更新、booksテーブルの更新、そして最後に制約の再確立が含まれます。全体として、これは苦痛の種です。独自の内部値を主キーとして使用すれば、問題はなくなります。第三者が同行して、スキーマを変更するように勝手に指示することはできません。私たちは独自のキースペースを制御しています。また、ISBNなどの変更が必要な場合でも、データベース内の既存の関係に影響を与えることなく変更できます。実際には、行の編成をそれらの行のデータの外部表現から切り離しました。

説明はかなり本っぽいですが、私はそれが物事をより簡単な方法で説明すると思います。

2
Mohit Jain

...データベースが非効率的な方法でIDフィールドを処理する方法と、データベースがインデックスを作成するときに、ツリーのソートに欠陥があります...

これはほぼ間違いなくナンセンスでしたが、異なるセッションからPKにインクリメントする数値を高いレートで割り当てるときのインデックスブロックの競合の問題に関連している可能性があります。その場合は、REVERSE KEYインデックスが役立ちますが、ブロック分割アルゴリズムの変更によりインデックスサイズが大きくなります。 http://download.Oracle.com/docs/cd/B19306_01/server.102/b14220/schema.htm#sthref998

特に、ツールセットを使用してより迅速な開発を支援する場合は、合成を行います。

2
David Aldridge

あずきっく

議論に必要なバランスを提供してくれてありがとう。特に、DOMAINsに関する情報に感謝します。

一貫性を保つために、実際にはシステム全体で代理キーを使用していますが、areのトレードオフが関係しています。サロゲートキーを使用して呪う最も一般的な原因は、正規値の短いリストを含むルックアップテーブルがある場合です-使用するスペースが少なく、値を作成しただけの場合、すべてのクエリがより短く/簡単/高速になりますテーブルに結合する代わりにPKを使用します。

1
Hank Gay

両方を実行できます。大企業のデータベースは、1回限りのクエリやデータインポートを実行する人間のDBAを含む複数のアプリケーションで使用される可能性が高いため、ORMシステムの利益のためだけに設計することは、必ずしも実用的または望ましいとは限りません。

私が最近行う傾向があるのは、各テーブルに「RowID」プロパティを追加することです。このフィールドはGUIDであり、各行に固有です。これは主キーではありません-これは自然キーです(可能な場合)。ただし、このデータベースの上で動作するORMレイヤーは、RowIDを使用して派生オブジェクトを識別できます。

したがって、次のようになります。

 CREATE TABLE dbo.Invoice(
 CustomerId varchar(10)、
 CustomerOrderNo varchar(10)、
 InvoiceAmount money not null、
 Comments nvarchar (4000)、
 RowId uniqueidentifier not null default(newid())、
 
 primary key(CustomerId、CustomerOrderNo)
)

したがって、DBAは幸せで、ORMアーキテクトも幸せで、データベースの整合性は維持されます。

1
Keith Williams

ここで、リレーショナルデータベースで自動生成された整数IDフィールドを説明するときにカバーされないものを追加したいと思っただけです(それらが頻繁に表示されるため)。つまり、ベースタイプは、ある時点でオーバーフローする可能性があります。

これで自動的に複合IDが自動的に作成されるとは言いませんが、テーブルに論理的に追加できるデータ(まだ一意です)であっても、単一の自動生成された整数であるというのは事実です。アイデンティティはこれが起こるのを防ぐことができます。

はい、私はほとんどの状況でそれはありそうもないことを理解しています、そして64ビット整数を使用することはあなたに多くのヘッドルームを与えます、そして現実的にはこれまでのようなオーバーフローが起こったならばデータベースはおそらく異なって設計されるべきでした。

しかし、それは誰かがそれをするのを妨げません...特定のファーストフード会社のグローバルレベルですべてのトランザクションを格納することが期待されるIDとして単一の自動生成された32ビット整数を使用するテーブルは失敗しますそれが挿入しようとするとすぐに、2,147,483,648番目のトランザクションです(これは完全に実行可能なシナリオです)。

これは注意すべき点です。人々はつまらないか完全に無視する傾向があります。定期的にテーブルが挿入される場合は、時間の経過とともに蓄積されるデータの頻度と量、および整数ベースの識別子を使用する必要があるかどうかについて検討する必要があります。

0
Xorcist