常に単一の整数列を主キーとして持つことの欠点は何ですか?


18

私が取り組んでいる1つのWebアプリケーション内で、すべてのデータベース操作は、Entity Framework ORMで定義されたいくつかの汎用リポジトリを使用して抽象化されています。

ただし、汎用リポジトリのシンプルなデザインを実現するには、関連するすべてのテーブルで一意の整数(Int32C#、intSQL)を定義する必要があります。これまで、これは常にテーブルのPKであり、IDENTITY

外部キーは頻繁に使用され、これらの整数列を参照します。これらは、一貫性とORMによるナビゲーションプロパティの生成の両方に必要です。

通常、アプリケーション層は次の操作を実行します。

  • テーブルからの初期データロード(*)-SELECT * FROM table
  • 更新 -UPDATE table SET Col1 = Val1 WHERE Id = IdVal
  • 削除 -DELETE FROM table WHERE Id = IdVal
  • 挿入 -INSERT INTO table (cols) VALUES (...)

頻度の低い操作:

  • 一括挿入 - BULK INSERT ... into tableその後に(*)すべてのデータロード(生成された識別子を取得するため)
  • 一括削除 -これは通常の削除操作ですが、ORMの観点からは「一括」です。DELETE FROM table where OtherThanIdCol = SomeValue
  • 一括更新 -これは通常の更新操作ですが、ORMの観点からは「一括」です。UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue

*すべての小さなテーブルはアプリケーションレベルでキャッシュされ、ほとんどすべてSELECTsがデータベースに到達しません。典型的なパターンは、初期ロードと多数のINSERTs、UPDATEs、DELETEsです。

現在のアプリケーションの使用状況に基づいて、どのテーブルでも1億レコードに達する可能性は非常にわずかです。

質問: DBAの観点から見ると、このテーブル設計の制限があると、重大な問題が発生しますか?

[編集]

回答(素晴らしいフィードバックをありがとう)と参考記事を読んだ後、詳細を追加する必要があるように感じます。

  1. 現在のアプリケーションの詳細 -モデルを他のアプリケーションにも再利用できるかどうかを理解したいので、現在のWebアプリケーションについては触れませんでした。ただし、私の特定のケースは、DWHから多くのメタデータを抽出するアプリケーションです。ソースデータは非常に乱雑で(奇妙な方法で非正規化され、いくつかの不整合があり、多くの場合自然な識別子がありません)、私のアプリは明確に分離されたエンティティを生成しています。また、生成された識別子(IDENTITY)の多くが表示されるため、ユーザーはそれらをビジネスキーとして使用できます。これは、大規模なコードのリファクタリングに加えて、GUIDの使用を除外します

  2. 「行を一意に識別する唯一の方法であってはなりません」(Aaron Bertrand♦)-これは非常に良いアドバイスです。また、すべてのテーブルでUNIQUE CONSTRAINTを定義して、ビジネスの重複が許可されないようにします。

  3. フロントエンドアプリ駆動設計とデータベース駆動設計 -設計の選択はこれらの要因によって引き起こされます

    1. Entity Frameworkの制限 -複数の列PKは許可されます、値は更新できません

    2. カスタム制限 -単一の整数キーを持つことで、データ構造と非SQLコードが大幅に簡素化されます。たとえば、すべての値リストには整数キーと表示値があります。さらに重要なことは、キャッシュ用にマークされたテーブルがUnique int key -> valueマップに入れられることを保証します。

  4. 複雑な選択クエリ -すべての小さな(20〜30K未満のレコード)テーブルデータがアプリケーションレベルでキャッシュされるため、これはほとんど発生しません。これにより、アプリケーションコードを書くときの生活が少し難しくなります(LINQを書くのが難しくなります)が、データベースのヒットはずっと良くなります。

    1. リストビュー - SELECTロード時にクエリ(すべてがキャッシュされます)または次のようなクエリを生成しません。

      SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)

      他のすべての必要な値はキャッシュルックアップ(O(1))を通じてフェッチされるため、複雑なクエリは生成されません。

    2. ビューの編集 -次のSELECTようなステートメントを生成します

      SELECT allcolumns FROM BigTable WHERE PKId = value1

(すべてのフィルターと値はintsです)


システム生成のサロゲート値を持つ列の使用に関して、論理的、物理的、および実用的な側面が議論されているため、これらの関連記事を見つけることができます。
MDCCL

回答:


19

追加のディスクスペース(およびメモリ使用量とI / O)を除いて、IDENTITY列を必要としないテーブル(IDENTITY列を必要としないテーブルの例)に追加しても、実際にははありません。ユーザーを自分の権限にマッピングするようなシンプルなジャンクションテーブルです)。

2010年のブログ投稿では、すべてのテーブルにそれらを盲目的に追加することをやめました。

ただし、サロゲートキーには有効なユースケースがあります-一意性を保証すると仮定しないように注意してください(追加される理由もあります- 行を一意に識別する唯一の方法であってはなりません)。ORMフレームワークを使用する必要があり、実際のキーが整数でも、単一列でもない場合でも、ORMフレームワークで単一列整数キーが必要な場合は、必ず一意の制約/インデックスを定義してくださいあなたの本当の鍵にも。


早速のお返事ありがとうございます。はい、アプリケーションはORM(EF)を使用します。単一の整数列キーは必要ありませんが、この制限を導入して、いくつかの一般的な操作をはるかに簡単にします(設計上)。また、すべてのアプリケーションキャッシュは、キー(キー)が高速に取得できるように、すべてをマップ(辞書)に保存します。キーは一意である必要があります。GUIDよりもintを選択しているため、挿入するテーブルにはIDENTITYを使用する必要があります。固定値テーブルの場合、IDENTITYは必要ありません。
アレクセイ

自然キーの一意性チェックを回避する必要があるケースがいくつかあると思います。GISデータを扱う人として、すぐに思い浮かぶのは、自然のキーがジオメトリ自体か、ジオメトリと外部キーのどちらかであるということです。正確なジオメトリで物事を調べることは常に非実用的であるため、それに対する一意性の制約はあまり役に立たない可能性が高く、パフォーマンス上の欠点があります。自然キーの一部が長いテキスト列である場合も同様です。しかし、私は同意します。実用的である場合はいつでも、はい、自然キーに対する一意の制約が適用されるべきです。
jpmc26

13

私の経験から、すべてのテーブルに個別のIDを使用する主で圧倒的な理由は次のとおりです。

ほぼすべての場合、顧客は、一部の外部の「自然」フィールドXYZBLARGH_IDが永久に一意であり、特定のエンティティに対して決して変わらず、再利用されないという構想段階で誓約を誓いました。主キーのプロパティが壊れていました。それだけではうまくいきません。

次に、DBAの観点から見ると、DBを遅くしたり肥大化したりすることは、行ごとに4バイト(または何でも)ではなく、誤ったインデックスまたは欠落したインデックス、忘れたテーブル/インデックスの再編成、間違ったRAM /テーブルスペースチューニングパラメーターなどです、バインド変数などの使用を怠ります。それらは、追加のID列ではなく、10、100、10000の要因でDBの速度を低下させる可能性があります。

そのため、行ごとに32ビットを追加することの技術的で測定可能な欠点があったとしても、IDを離れて最適化できるかどうかの問題ではありませんが、ある時点でIDが不可欠になるかどうかは問題ではありませんありそうもない。そして、ソフトウェア開発のスタンスによるすべての「ソフト」なメリットを数えるつもりはありません(ORMの例や、設計上のすべてのIDが同じデータ型などである場合、ソフトウェア開発者にとって簡単になるという事実) 。

注:n:m関連付けテーブルに個別のIDは必要ありません。そのようなテーブルでは、関連付けられたエンティティのIDが主キーを形成する必要があるためです。反例としては、奇妙な理由で同じ2つのエンティティn:m複数の関連付けを可能にする奇妙な関連付けがあります。その場合、PKを作成するには独自のID列が必要になります。そこている彼らは、このようなAライブラリと仕事をしなければならない場合には、開発者との寛大なる理由になるので、けれども複数列のPKを扱うことができないORMライブラリが。


2
「同じ2つのエンティティ間の複数の関連付けを可能にする奇妙なn:m関連付け」は、実際には非常に一般的です。たとえば、人が車を所有している場合、所有権の開始時と終了時に要件が記録されるように変更されます(人は車を販売して後で購入し、ソフトウェアをクラッシュさせることができます....)
イアンリングローズ

うん、そのようなもの、@ IanRingrose。
AnoE

6

常に意味のない余分な列をすべてのテーブルに追加し、それらの列のみを外部キーとして参照する場合、ほぼ必然的にデータベースがより複雑で使いにくくなります。事実上、ユーザーにとって重要なデータを外部キー属性から削除し、ユーザー/アプリケーションに追加の結合を強制して同じ情報を取得させます。クエリはより複雑になり、オプティマイザーの仕事は難しくなり、パフォーマンスが低下する可能性があります。

テーブルには、本来のデータよりも「実際の」データがまばらに入力されます。したがって、データベースの理解と検証がより困難になります。また、特定の有用な制約を強制することが困難または不可能である場合があります(制約には、同じテーブルに存在しない複数の属性が含まれます)。

適切な理由がある場合にのみ、より慎重にキーを選択し、整数にすることをお勧めします。独断的なルールに頼るのではなく、優れた分析、データの整合性、実用性、検証可能な結果に基づいてデータベース設計を行います。


1
それでも、多くのシステムでは、すべてのテーブル(たとえば、これまでに作成されたほぼすべてのRuby on Railsアプリ)に合成整数主キーがありますが、このような問題はありません。また、主キーへの変更(決して発生することはなかった)をすべての外部キーテーブルにプッシュする必要があるという問題もありません。
デビッドアルドリッジ

2
質問は不利な点を求めたので、私の答えです。賢明に使用すれば、代理キーが意味をなすことを否定しません。しかし、3、4、5(またはそれ以上)の無意味な外部キーを持つテーブルを見てきました。したがって、それらから有用な結果を得るには、3、4、5以上の結合が必要です。より実用的な設計では、結合をまったく必要としなかったかもしれません。
nvogel

1
このようなデザインで人々が抱える主な問題は、そのようなクエリの実行だとは確信していません。それは、しばしば反対するクエリの記述です。
デビッドアルドリッジ

5

さまざまなデータベースでの私の経験では、整数の主キーは、キーまったく定義されていないアプリケーションよりも常に優れています。または、論理的ではない厄介な方法で半ダースのvarchar列を結合するキーがあります... (ため息)

整数PKからGUIDに切り替えたアプリケーションを見てきました。その理由は、特定の場合に複数のソースデータベースのデータをマージする必要があるためです。開発者は、すべてのキーをGUIDに切り替えたため、マージの一部ではなかったテーブルでも(データが将来のマージの一部になった場合に備えて)データの衝突を恐れずにマージを実行できます。

整数PKは、別のソースからのデータをマージするか、整数サイズの制限を超えるデータがある場合を除いて、あなたを噛まないだろうと思います-挿入のためのスペースがなくなるまで、それはすべて楽しいゲームです。

私はそれがあること、けれども、言うことができ、テーブルがより頻繁に道その照会する場合は、あなたのPK以外の列にあなたのクラスタ化インデックスを設定しても意味が。ただし、特に更新と選択の大部分がPK値に基づいている場合、これは異常なケースです。


2
すべてのキーをGUIDに変更するという恐ろしい理由のように聞こえます。現在、すべての代理キーにGUIDを使用するデータベースを使用しています。
アンディ

2
いいえ。GUIDを使用するのは楽しいことではありません。私はそれらが好きではありませんが、特定のユースケースではそれらの価値を尊重します。
CaM

2

脇に置く:

  • 宗教戦争(グーグルサロゲートvs自然キー)
  • テーブルで定義するクラスター化インデックスの別の問題
  • すべてのデータをキャッシュする可能性

必要に応じて一括削除/更新を使用し、そのような操作をサポートするインデックスがある場合、使用するPK標準のために問題が発生することはないと思います。
後でEFで結合などのクエリを生成する場合、自然なキーベースのリポジトリの場合ほど効率的ではない可能性がありますが、どちらの場合でもその領域について十分に知りません。


4
自然キーでの結合が整数での結合よりも効率的な単一のケースを考えることはできません-多くの自然キーは4バイトより小さくすることはできず、もしそうであれば、十分な一意性はありません違いを作るための行。
アーロンバートランド

有能で最適化可能なSQLについては同意しますが、SQLジェネレーターの制限について言及していました。この分野での私の唯一の経験は、EFがスプーンで供給できる広範なビューを作成するように求められていることです。ただし、.net開発者はEFについて十分な知識を持っていなかったか、他の理由がありました。
TH

@AaronBertrandより効率的になる唯一の方法は、結合がまったく必要ない場合です。自然キーの使用を検討する唯一の場所は、ISO4127通貨コード(人間が認識できる)などの標準コードリストを使用することです。GBP、EURなどを通貨コードの主キーまたは代替キーの外部キーとして使用する場合がありますテーブル。
デビッドアルドリッジ

@Davidもちろん、参加が必要な場合について話していました。自然キーは変更される可能性があるため、関連するすべてのテーブルで自然キーを拡散させたくない場合が多くあります。これは苦痛なことです。
アーロンバートランド

うーん、サロゲートよりも自然な外部キーを宣伝していると誤解されることがあると思います。明確にするために、実際にそれらに言及したのは、a)Alexeiの質問を「自然キーを使用しないのは問題ですか?」、b)Alexeiのまとめの質問は「DBAの観点から」で始まり、私はc)複数の視点があることを認める必要があると感じました。c)使用するORM機能が主に選択を決定すると思うからです(実際に違いを生むことができる場合)。私は、代理の外国人キーキャンプにしっかりといます。
TH

2

あなたを導くのに役立ついくつかの要因があります、

  1. 定義と仕様。

    タスクまたは物理法則によって何かが一意であると定義されている場合、サロゲートキーで時間を浪費しています。

  2. 一意性。

    個人的な健全性、結合、および高レベルのデータベース機能には、(a)一意の列、(b)一意の列のシリーズのいずれかが必要です。

    すべての十分に正規化されたスキーマ(1NF)は、次のいずれかを提供します。そうでない場合は、常に作成する必要があります。日曜日にボランティアをする名簿があり、姓と名が含まれている場合、ジョーボブが2人いることを知りたいでしょう。

  3. 実装と最適化。

    intは、比較と同等性が速い小さなデータ形式になる傾向があります。照合順序がロケール(場所と言語)に依存する可能性があるUnicode文字列と比較してください。ASCII / UTF8文字列に4242を保存するのは4バイトです。2バイトに収まる整数として保存します。

そのため、マイナス面に関しては、いくつかの要因があります。

  1. 混乱とあいまいさ。

    1. @Aaron Bertrandブログのエントリはこれをうまくまとめています。それは持っている自己文書ではありません受注を仕様し、タスクによって、その後、「課す受注コードをデータベースの実装を通じて」。時にはそれを明確にするか、規約を作成する必要がありますが、これは混乱を招く可能性があります。
  2. スペース。

    整数はまだ行にスペースを追加します。そして、あなたがそれらを使用していないなら、目的はありません。

  3. クラスタリング。

    データは一方向にのみ注文できます。不要な代理キーを課す場合、その方法でクラスター化するのですか、それとも自然キーの方法でクラスター化するのですか?


長所と短所があります。
アレクセイ

@Alexeiありがとう、探しているものに合う場合は、選択済みとしてマークすることを検討してください。または、説明を求めます。
エヴァンキャロル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.