ここでの定義のゆるさを許しませんが、私は単純な概念を探求しようとしています。
主キーは行を一意に識別します。テーブルには一意の値を持つ他の列が存在する可能性があるため、行(候補キー)を一意に識別できますが、タスクに指定されているのは主キーです。
主キーをより便利にするプロパティには、次のものがあります。
これらの理由から、主キーには固有の値を持たないことをお勧めします。そのため、値を変更またはリサイクルする理由は決してありません。つまり、それ以外の場合は無意味である必要があります。
名前に基づいたクライアントコードなど、ある種のコードを含む主キーを見てきました。明らかな問題は、(a)クライアント名が変更されるとPKも変更されること、(b)類似した名前のクライアントと競合するリスクが高すぎることです。
半分の例外は、シーケンス番号の小さな意味を持つ自動インクリメント番号の使用です。しかし、それはまだ安定しています。
問題は、どのような状況で、主キーを他の本当の意味で使用する方が好ましい場合があるでしょうか。つまり、PKは任意である必要があり、通常はシーケンス番号で十分であるというアドバイスに問題はありますか?
が他の実際の意味を持つ主キーを使用するのが好ましい場合、どのような状況下でですか? (強調を追加)
この質問の焦点は「好ましい」であり、「受け入れられない」であり、これが依然として非常に主観的なトピックであることを受け入れると、システムがtrulyさまざまな理由からの自然なキー(そのほとんどは、ポールが質問へのコメントでリンクした他の回答で以前に述べられています):
(真に)強調するのは、newサロゲートキーを使用したくない2つの状況があるためです。
ブリッジテーブル
(または、多対多の関係を表すためにのみ、または主に使用されるテーブルを呼び出すのに好きなもの)
Thing ThingXTag Tag
------ --------- ---
ThingID INT AutoMagic PK ---> ThingID INT PK, FK
Stuff SomeType TagID INT PK, FK <--- TagID INT AutoMagic PK
TagName VARCHAR
ブリッジテーブル(論理モデルには存在しないが物理モデルには必要なテーブル)をモデリングする場合、PKには、このテーブルを介して関連付けられているテーブルの既存の主キー列が必要です。これにより、個別の一意のインデックス/制約を必要とせずに、値の適切な一意性と非NULL性を適用できます。この関係の外部キーが必要になるというまれなケースでは、次のようになります。
WackyTable ThingXTag
---------- ---------
WackyTableID INT AutoMagic PK
ThingID INT FK ---> ThingID INT PK, FK (to Thing.ThingID)
TagID INT FK ---> TagID INT PK, FK (to Tag.TagID)
AttributeX VARCHAR InsertDate DATETIME
InsertDate DATETIME
これらのブリッジテーブルに独自の自動インクリメントサロゲートキーPKがあり、ブリッジテーブルの単一列サロゲートキーがFKを介して他のテーブルで参照されているシステムで作業しました。
WackyTable ThingXTag
---------- ---------
WackyTableID INT AutoMagic PK
ThingXTagID INT FK ---> ThingXTagID INT AutoMagic PK
AttributeX VARCHAR ThingID INT FK (to Thing.ThingID)
InsertDate DATETIME TagID INT FK (to Tag.TagID)
InsertDate DATETIME
デバッグなどに時間をかけすぎたのは恐ろしくて混乱する混乱でした。
兄弟テーブル
これらは真に単一のエンティティであり、1対1の関係を持つテーブルです。これらは、パフォーマンス上の理由から、2つ(または必要に応じてそれ以上)のテーブルに分割されるだけです。 100万(またはそれ以上)の行があるテーブルでこれを実行しました。非常に幅が広いか、適度に幅が広いか、そしてあまり頻繁に使用されていない列があった場合または50バイトを超える文字列でした。そのようなもの。これにより、エンティティのコアプロパティが、各データページにより多くの行に収まる狭いテーブルに保持されます。
これらの場合、「兄弟」テーブルは最初のテーブルとまったく同じレベルにあり、同じPK
を持つ必要があります。各行には最初のテーブルの自然キーに相当するものがあるため、自動インクリメントサロゲートキーを指定しても意味がありません。
Product ProductProperty
------- ---------------
ProductID INT AutoMagic PK ---> ProductID INT PK, FK (to Product.ProductID)
Name VARCHAR ShortDescription VARCHAR
SKU VARCHAR SomethingElse SomeType
Quantity INT UpdateDate DATETIME
CreateDate DATETIME
UpdateDate DATETIME
明確にするために、概念モデルではなく、物理モデルの観点から話しています。この質問は、概念的に存在しない問題(代理キー、主キー値の使用に関する問題など)の枠内にあるため、この質問の焦点は物理モデルであると想定しました。そのことを念頭に置いて、自然キーを保存して、識別に使用しないでください。それどころか、自然キーは優れた「代替キー」であり、一意の制約/インデックスが設定されている必要があります。ただし、概念モデルの理想主義は必ずしも物理モデルに直接変換されるとは限りません。データの整合性(つまり、データモデルの安定性と信頼性)は、物理モデルの最優先事項であり、そうでない場合最優先事項です。そのため、代理キーの使用などの実際的な考慮事項は、この目標が達成され、侵害されないことを保証するために行われる必要があります。つまり、SSNやSKUなどがある場合は、それらに一意の制約がある列に絶対的に格納し、システムにthat値の検索を自動で実行させる-生成された数値はとにかく外部で使用しないでください。ユーザーは、レコードの自動生成されたID番号を知る必要はありません。ユーザーは、知っている値を渡す必要があります(例:UserID/CustomerIDのルックアップとしてのメールアドレス、フライト確認コードとフライト日付の組み合わせなど)。システムはそれを、その時点から使用する自動生成値に変換する必要があります。
はい、この回答の冒頭に記載されている問題は、ナチュラルキーを代替キーとして使用する場合の潜在的な問題です。ただし、違いは、問題が(通常)1つのテーブルにのみ分離されることです。誰かがミスをして「フライトロケーター」に一意のインデックスを作成した場合、違反が発生するまでに時間がかかることがあります。しかし、そうすると、その一意のインデックスを削除し、フライトの日付を含めるように再作成するのも簡単です。または、システムでメールアドレス(多くの場合、ログインとして使用されます)を変更し、それが何年も前に(合法的に)他のユーザーによって使用されていたためにエラーが発生した場合、サポートへの影響/リスクなしにサポートによって処理される可能性が高いです。既存の関連レコード。どちらの場合も、残りのデータモデルは必要な変更のために変更されません。
繰り返しになりますが、これは実際的なアプローチです。
PSNとしてSSN(米国の社会保障番号)を使用したシステムがいくつあるかはわかりませんが、一部のシステムでは(おそらく、多くの場合)、本来あるべきほど一意ではないという問題を回避している可能性があります。しかし、これらのシステムはどれも、より安全に処理する必要性に関する長年にわたる変更を回避できませんでした。 SSNを代替キーとして扱うシステムでは、これらの値の暗号化に切り替えるための開発時間はほとんど必要ありません。また、システムは、データレイヤーで変更を行うためのダウンタイムをほとんど(またはまったく)必要としません。私たち全員には決して到達することのないプロジェクトのバックログがあることを考えると、企業はこれらの煩わしいが避けられない変更が20〜40ではなく5時間かかることを好む傾向があります(変更をテストする必要があることを忘れないでください。変更の範囲は、プロジェクトに必要なQA時間にも直接影響します)。
明確にするために、自然なキーを持つことが「許容可能」であるシナリオがいくつかありますが、「好ましい」とまでは言えません。
INT
と同じ量のスペースを使用します。バイナリ照合順序(_BIN2
、または_BIN
で終わるものもありますが、_BIN2
が推奨されます)を使用している場合は、速く比較する必要があります。このようなコードに比較的意味のある値を設定すると、サポート/デバッグが容易になります。ただし、時間の経過とともに部門名などが変更され、コードが意味をなさなくなる可能性があります。テーブルのすべてのキーは、そのテーブルの行を識別します。 DBMSは、キー(別名候補キー)に一意性制約を適用し、一意性を保証します。これにより、行がキー属性によって識別可能になることが保証されます。 2番目の段落は、主キーだけが識別の役割を果たすという誤解を示唆しています。
データベースを効果的に使用するには、通常、データベースの情報を実際のオブジェクトまたは概念に関連付ける何らかの方法が必要です。キーを使用すると、データベース内のファクトを個別に識別して、説明する現実の世界に関連付けることができるため、キーを使用してそれを実行できます。データベースが現実世界を正確に、すべて、またはほとんどすべてをモデル化するために、テーブルには「自然な」キーが必要になります-ある意味で意味のあるキーそれらが発見されて使用され、データベース内だけでなくデータベース外でも関連性があること。
主キーは特別なタイプのキーではありません。これは、テーブルのキーの1つです。テーブルにキーが1つしかない場合、主キーの選択は行われません。テーブルに複数のキーがある場合、通常は「主」キーが慣例や好みの理由で指定されますが、主キーを選択する個人の理由はさまざまで、主観的であり、矛盾する場合もあります。すべての場合において、keysの選択が重要です。キーの使い方は重要です。 「主」キーの選択は、通常、それほど重要ではありません。
私の意見は「ほとんどない」です。何かに意味がある場合、現実がデータから逸脱した場合に変更の可能性があり、外部キーやその他のそのような乱雑さにもかかわらず、カスケード更新に対処する必要があります。おそらく、少なくとも99%の確率で、主キーとして代理ID列を追加することにしました。残りの1%の時間は、通常、他のテーブルのサロゲートキーやタイムスタンプ(あるいはその両方のID列が適切な場合はまれにそれ自体のID列)のいくつかの組み合わせで構成される複合キーを持つ関連テーブルで構成されます。
一意性を強制し、セマンティクスをデータを操作するユーザーに伝えたい自然キーがある場合は、追加の一意の代替キーインデックスを作成することを検討してください。私は通常、意図を明確にするために、インデックス名の前にAK_を付けます。インデックスは、ルックアップクエリにメリットをもたらし、データの整合性を維持し、特定のキー値のクエリからは1行のみが予期されることを明確にします。
その間、無意味な代理キーに基づいてすべての販売ドキュメントを結合できます。また、販売中の女性の1人が結婚した場合(その道を何度も通っている場合)は、カスケード名の変更をあちこちで処理する必要はありません。 。