15

3 層の情報を取得します。

レイヤー 1: 情報

このレイヤーには、UNIQUE自然なインデックスと簡単に転送できる代理キーを持つデータが含まれています。

Table Surnames:

+-----------------------------+--------------+
|    ID (Auto Increment, PK)  |    Surname   |
+-----------------------------+--------------+
|               1             |     Smith    |
|               2             |    Edwards   |
|               3             |     Brown    |
+-----------------------------+--------------+

Table FirstNames

+-----------------------------+--------------+
|   ID (Auto Increment, PK)   |   FirstName  |
+-----------------------------+--------------+
|               1             |     John     |
|               2             |     Bob      |
|               3             |     Mary     |
|               4             |     Kate     |
+-----------------------------+--------------+

ナチュラルキー

または、Mike Sherrill が説明しているように、上記の 2 つのテーブルをなくしIDて、Surname と FirstName を Natural Primary Key として使用することもできます。varcharこの場合、ではなく参照の下のレイヤーを想定しますint

レイヤー 2: 人

このレイヤーでは、複合インデックスが使用されます。この値は、代理キーが主キーとして使用されているかどうかに応じて、UNIQUEまたはになります。PRIMARY

+-----------------+--------------+
|    FirstName    |    LastName  |
+-----------------+--------------+
|        1        |       2      |
|        1        |       3      |
|        2        |       3      |
|        3        |       1      |
|        4        |       2      |
|       ...       |      ...     |
+-----------------+--------------+

レイヤー 3: 親

この層では、人々の間の関係がParentsOfテーブルを通して調査されます。

ParentsOf

+-----------------+-----------------+
|      Person     |   PersonParent  |
+-----------------+-----------------+

 OR

+-----------------+-----------------+-----------------+-----------------+
| PersonFirstName |  PersonSurname  | ParentFirstName |  ParentSurname  |
+-----------------+-----------------+-----------------+-----------------+

質問

参照整合性が私にとって非常に重要であると仮定すると、FOREIGN KEYSこれらのインデックスを使用して、データベースがこの面での整合性を監視する責任を負うようにし、ORM を使用する場合は、複合主キーをネイティブにサポートするDoctrineのようなものです...

理解するのを手伝ってください:

  • 第 1 層で代理キーと自然キーを使用する場合に生じるトレードオフのリスト。

  • 第 3 層に転送できる第 2 層の複合キーと代理キーを使用する場合のトレードオフのリスト。

このトピックに関して専門家の間で大きな意見の相違があり、それが宗教戦争を引き起こす可能性があることを理解しているため、どちらが優れているかを聞くことに興味はありません. 代わりに、非常に単純かつ客観的に、人間が可能な限り客観的に、代理キーを各レイヤーに渡すことと、主キー (自然/複合、または代理/複合) を維持することによって、どのようなトレードオフを行うかを尋ねています。SOや他のWebサイトで代理キーを絶対に使用しない、または常に使用する言っいる人を誰でも見つけることができます。代わりに、トレードオフの合理的な分析が、あなたの回答で最も高く評価されます。

編集:姓の例は 6NF の使用例として不適切であることが指摘されています。質問をそのままにしておくために、そのままにしておきます。このユースケースを想像するのが難しい場合は、「食料品」のリストの方が適しているかもしれません。別名:

+-----------------------------+--------------+
|   ID (Auto Increment, PK)   |   Grocery    |
+-----------------------------+--------------+
|               1             | Sponges      |
|               2             | Tomato Soup  |
|               3             | Ice Cream    |
|               4             | Lemons       |
|               5             | Strawberries |
|               6             | Whipped Cream|
+-----------------------------+--------------+

+-----------------------------+--------------+
|   ID (Auto Increment, PK)   |   Brand      |
+-----------------------------+--------------+
|               1             | Bright       |
|               2             | Ben & Jerry's|
|               3             | Store Brand  |
|               4             | Campbell's   |
|               5             | Cool Whip    |
+-----------------------------+--------------+    

自然複合キーの例:

+-----------------------------+--------------+
|           Grocery           |   Brand      |
+-----------------------------+--------------+
|           Sponges           | Bright       |
|           Ice Cream         | Ben & Jerry's|
|           Ice Cream         | Store Brand  |
|           Tomato Soup       | Campbell's   |
|           Tomato Soup       | Store Brand  |
|           Lemons            | Store Brand  |
|           Whipped Cream     | Cool Whip    |
+-----------------------------+--------------+ 

おすすめのペアリング

+-----------------+-----------------+-----------------+-----------------+
|     Grocery1     |  Brand1        | Grocery2        |  Brand2         |
+-----------------+-----------------+-----------------+-----------------+

繰り返しますが、これも単なる例です。これは私が進めることをお勧めする方法ではありませんが、私の質問を説明するのに役立つはずです.

この方法には欠点があります。繰り返しますが、この質問は、以下の各方法の利点と欠点を説明するためのものであり、いずれかが優れていると強調するためのものではありません. ほとんどの人は、この特定の例の疑わしい性質を無視して、核となる質問に答えることができたと思います。この編集はできない人のためのものです。

以下に非常に優れた回答がいくつかあります。どの方向に進むべきか興味がある場合は、それらを読んでください。

編集終了

ありがとうございました!

4

8 に答える 8

26

ここにいくつかのトレードオフがあります:

単一のサロゲート (人工的に作成):

  • すべての子テーブルの外部キーは、主キーを参照するために 1 つの列のみを必要とします。

  • すべての子テーブルを外部キーで更新する必要なく、テーブルの自然キーを非常に簡単に更新できます

  • 小さいプライマリ/外部キー インデックス (つまり、広くない) これにより、データベースの実行が高速化されます。たとえば、親テーブルでレコードが削除された場合、子テーブルを検索して、孤立したテーブルが作成されないようにする必要があります。狭いインデックスはスキャンが高速です (見た目だけ)。

  • ほとんどの場合、データに存在する自然キーにもインデックスを付けたいと思うため、より多くのインデックスが必要になります。

自然複合キー付きテーブル:

  • データベース内のインデックスが少ない

  • データベース内の列が少ない

  • シーケンスジェネレーターを取得する必要がないため、大量のレコードを簡単かつ迅速に挿入できます

  • コンパウンド内のキーの 1 つを更新するには、すべての子テーブルも更新する必要があります。

次に、別のカテゴリがあります: 人工複合主キー

これが理にかなっている例を 1 つだけ見つけました。行レベルのセキュリティのために、すべてのテーブルのすべてのレコードにタグを付ける必要がある場合。

たとえば、50,000 クライアントのデータを格納するデータベースがあり、各クライアントが他のクライアントのデータを参照することは想定されていないとします。これは、Web アプリケーション開発では非常に一般的です。

各レコードがclient_idフィールドでタグ付けされている場合、行レベルのセキュリティ環境を作成しています。ほとんどのデータベースには、正しくセットアップされた場合に行レベルのセキュリティを適用するためのツールがあります。

最初に行うことは、主キーと外部キーのセットアップです。通常、テーブルにidは主キーとしてフィールドがあります。キーを追加することclient_idで、複合キーになりました。client_idそして、すべての子テーブルに運ぶ必要があります。

複合キーは 2 つの代理キーに基づいており、クライアント間およびデータベース全体でデータの整合性を確保する防弾の方法です。

この後、ビュー (または Oracle EE セットアップ仮想プライベート データベースを使用している場合) およびその他のさまざまな構造を作成して、データベースが行レベルのセキュリティを適用できるようにします (これはすべて独自のトピックです)。

このデータ構造はもはや n 次まで正規化されていません。各 pk/fkのclient_idフィールドは、通常のモデルを非正規化します。このモデルの利点は、データベース レベルで行レベルのセキュリティを簡単に適用できることです (これはデータベースが行うべきことです)。client_idすべての選択、挿入、更新、削除は、セッションが現在設定されているものに制限されます。データベースにはセッション認識機能があります。

概要

代理キーは常に安全な賭けです。セットアップにはもう少し作業が必要で、より多くのストレージが必要です。

私の意見では、最大のメリットは次のとおりです。

  • 1 つのテーブルで PK を更新できるため、他のすべての子テーブルは変更されることなく瞬時に変更されます。

  • データが台無しになった場合 (プログラミングのミスが原因である時点でそうなります)、代理キーを使用すると、クリーンアップがはるかに簡単になり、場合によっては、代理キーがあるためにのみ可能になります。

  • データベースが属性を検索して s.key を見つけ、単一の数値キーですべての子テーブルを結合できるため、クエリのパフォーマンスが向上します。

自然キー、特に複合 NKey は、コードを書くのが苦痛になります。4 つのテーブルを結合する必要がある場合、"where 句" は、単一の SKey を使用した場合よりもはるかに長くなります (そして混乱しやすくなります)。

代理キーは「安全な」ルートです。自然キーはいくつかの場所で有益です。データベース内のテーブルの約 1% と言えます。

于 2014-05-25T00:43:14.713 に答える
10

まず第一に、2 番目のレイヤーは少なくとも 4 つの異なる方法で表現でき、それらはすべて質問に関連しています。以下では、主に PostgreSQL 構文で疑似 SQL を使用しています。特定の種類のクエリでは、構造に関係なく、再帰と複数の追加インデックスが必要になるため、これについてはこれ以上説明しません。クラスター化インデックスをサポートする dbms を使用すると、ここでのいくつかの決定に影響を与える可能性がありますが、クラスター化インデックスでの 6 つの結合が、単一のカバー インデックスから値を読み取るよりも高速であると想定しないでください。テスト、テスト、テスト。

第 2 に、最初のレイヤーには多くのトレードオフがありません。外部キーは、宣言された列を参照できるnot null uniqueのとまったく同じ方法で、宣言された列を参照できますprimary key。代理キーにより、テーブルの幅が 4 バイト増加します。これは、すべてではありませんが、ほとんどのデータベース アプリケーションにとって簡単なことです。

第 3 に、正しい外部キーと一意の制約により、これら 4 つの設計すべてで参照整合性が維持されます。(ただし、以下の「カスケードについて」を参照してください。)

A. 代理キーへの外部キー

create table people (
  FirstName integer not null
    references FirstNames (ID),
  LastName integer not null
    references Surnames (ID),
  primary key (FirstName, LastName)
);

B. 自然キーへの外部キー

create table people (
  FirstName varchar(n) not null
    references FirstNames (FirstName),
  LastName varchar(n) not null
    references Surnames (Surname),
  primary key (FirstName, Surname)
);

C. 代理キーへの外部キー、追加の代理キー

create table people (
  ID serial primary key,
  FirstName integer not null
    references FirstNames (ID),
  LastName integer not null
    references Surnames (ID),
  unique (FirstName, LastName)
);

D. 自然キーへの外部キー、追加の代理キー

create table people (
  ID serial primary key,
  FirstName varchar(n) not null
    references FirstNames (FirstName),
  LastName varchar(n) not null
    references Surnames (Surname),
  unique (FirstName, Surname)
);

次に、ParentsOf テーブルを見てみましょう。

A. 上記の A の代理キーへの外部キー

create table ParentsOf (
  PersonFirstName integer not null,
  PersonSurname integer not null,
  foreign key (PersonFirstName, PersonSurname)
    references people (FirstName, LastName),

  ParentFirstName integer not null,
  ParentSurname integer not null,
  foreign key (ParentFirstName, ParentSurname)
    references people (FirstName, LastName),

  primary key (PersonFirstName, PersonSurname, ParentFirstName, ParentSurname)
);

特定の行の名前を取得するには、4 つの結合が必要です。"FirstNames" および "Surnames" テーブルに直接参加できます。名前を取得するために「People」テーブルに参加する必要はありません。

B. 上記 B の自然キーへの外部キー

create table ParentsOf (
  PersonFirstName varchar(n) not null,
  PersonSurname varchar(n) not null,
  foreign key (PersonFirstName, PersonSurname)
    references people (FirstName, LastName),

  ParentFirstName varchar(n) not null,
  ParentSurname varchar(n) not null,
  foreign key (ParentFirstName, ParentSurname)
    references people (FirstName, LastName),

  primary key (PersonFirstName, PersonSurname, ParentFirstName, ParentSurname)
);

この設計では、特定の行の名前を取得するために結合は必要ありません。多くの SQL プラットフォームでは、主キーのインデックスからすべてのデータを取得できるため、テーブルを読み取る必要はまったくありません。

C. 代理キーへの外部キー、上記の C の追加の代理キー

create table ParentsOf (
  Person integer not null
    references People (ID),
  PersonParent integer not null
    references People (ID),
  primary key (Person, PersonParent)
);

名前を取得するには、「people」テーブルを介して結合する必要があります。合計 6 つの結合が必要です。

D. 自然キーへの外部キー、上記の D の追加の代理キー

このデザインは、すぐ上の C と同じ構造です。D の "people" テーブルにはテーブル "FirstNames" と "Surnames" を参照する自然キーがあるため、テーブル "people" への 2 つの結合だけで名前を取得できます。

ORMについて

ORM は、SQL 開発者が SQL を記述する方法で SQL を構築しません。SQL 開発者が名前を取得するために 6 つの結合を必要とする SELECT ステートメントを作成した場合、ORM は同じデータを取得するために 7 つの単純なクエリを実行する傾向があります。これは問題になる可能性があります。そうではないかもしれません。

カスケードについて

サロゲート ID 番号は、すべての外部キー参照を暗黙的で宣言されていない "ON UPDATE CASCADE" にします。たとえば、姓のテーブルに対してこの更新ステートメントを実行するとします。. .

update surnames
set surname = 'Smythe'
where surname = 'Smith';

そうすれば、すべてのスミスがスミスになります。これを防ぐ唯一の方法は、「姓」の更新許可を取り消すことです。暗黙的で宣言されていない「ON UPDATE CASCADE」は、必ずしも良いことではありません。不要な暗黙の「カスケード」を防ぐためだけにアクセス許可を取り消すことは、必ずしも良いことではありません。

于 2014-05-25T05:12:40.953 に答える
2

ここでは、純粋な学術的な議論は避けて、実用的な考慮事項をいくつか見ていきます。これは、最新のデータベース設計では通常、スケーラビリティ、モビリティ (切断された操作)、および競合の解決を考慮する必要があり、キーの選択が大きな影響を与える可能性があるためです。

あなたの選択に影響を与える可能性のあるものは次のとおりです。

  • 同じ自然キーを持つ可能性のある個別のレコードを処理する方法。たとえば、同一の姓と名。
  • サーバーによって割り当てられた代理キーが使用されている場合、Web またはモバイル クライアントはどのように複雑なモデル グラフを保持しますか (何らかのマッピング レイヤーが必要です)。別の方法は、マッピングの問題を回避し、クライアントが割り当てた v4 UUID を使用することです。
  • 上記に続いて、モバイルアプリなどの一時的に切断された環境や、最初にサーバーと同期することなくクライアントが相互にピア/共有できる環境で、競合の解決にどのように対処しますか? オブジェクト ID は、これらの問題をサポートおよび解決するための重要な概念です。
  • データベースのシャーディングによるスケーラビリティは、キーの選択に基づいて簡単または困難になります。v4 UUID ベースの代理キーは簡単で、クライアントに割り当てることができますが、自動インクリメント代理キーはシャードするのが難しく、キーが衝突しないようにアプリオリに一定数のシャードを選択する必要があります。複合キーと自然キーは難しいものです。キーは比較的安定していますが、変更される可能性があり、シャード間でレコードを移行する機能が必要になるためです。
  • クライアントはオブジェクト ID をどのように管理していますか? 多くの場合、ユーザー インターフェイスでは、後で「クラウド内のサーバー」に永続化するために、モデルのローカル グラフを作成する必要があります。永続化前のこの期間、これらのオブジェクトには ID が必要であり、永続化後は、サーバー オブジェクト ID とクライアント オブジェクト ID の間の合意またはマッピングが必要です。
  • データベース上のすべてのもの (アプリケーション サーバーを含む) に ID マッピングの問題を処理するように強制したり、それをデータベース キーの設計に組み込んだり、データベースのスケーラビリティ/シャーディングの解決に役立てたりしますか?

私のアドバイスは、システム全体の特性を見て、理論的なデータベース設計を超えて、データベースの上にある自明ではないフルスタックでうまく機能するものに目を向けることです。主要な設計の選択によって、システムの使いやすさが左右され、開発の複雑さが増したり損なわれたりします。その結果、市場投入までの時間と、品質と信頼性の全体的なトレードオフが増減します。

于 2014-06-03T06:59:27.853 に答える
2

自然キーを使用すると、たとえば画面上に表示するために「自然な」値を見つけるために外部キー チェーンを最後まで結合する必要がないため、より簡単で高速なクエリを実行できます。

于 2014-05-26T10:52:54.500 に答える
1

この主キーの基準のリストを見たことがあります。この種の議論のかなり良い出発点だと思います

  • 個性的
  • 安定 (不変である必要はありません)
  • 還元不可能
  • 単純
  • 見慣れた

場合によっては、2 つ以上の基準が矛盾し、それらの間で妥協しなければならないことがあります。残念なことに、多くの人はキーの設計方法について考えることさえしません。ID 列、GUID など、ある種の自動生成されたキーを使用します。

代理キーの欠点の 1 つは、規則を宣言的に適用することがより困難になることです (ほとんどの DBMS はチェック制約でサブクエリをサポートしていません)。私は次のようなルールを考えています:

CHECK ( jobtitle <> 'BOSS' OR salary > 100 )

ただし、代理キーの最大の問題は、非常に奇妙な構造を回避でき、気付かないことです。

于 2014-05-29T04:00:51.120 に答える
1

複合キーが STUDENT 列と COURSE 列で構成されている場合、データベースは重複する値を入力しないようにします。

例。

複合キーでは、これは許可されません。データベースはそれを防ぎます。

STUDENT     COURSE
1           CS101
1           CS101

ただし、代理キーをキーとして選択した場合は、そのような重複を防ぐ別の方法を見つける必要があります。

フィールドのどの組み合わせが鍵となり得るかを考えると、問題をよりよく発見して理解するのに役立ちます。

于 2015-02-05T22:28:44.900 に答える
0

データに関して基本的なことを誤解していると思います。

1)単一の識別子(人名-人を一意に識別すると仮定)を取り、それをサブアトミックな部分に分割し、6NFのためにそれらを別々の関係変数に入れます。多くの場合、このような分割は実際的な理由で行われ、名/姓は一般的な例です。決定は通常、属性を再び組み合わせる場合と比較して、分割の複雑さ、頻度などに基づいて行われます。ここで分割は実用的ではありません。

2) 6NF は常に達成可能ですが、常に望ましいとは限りません。この場合、パーツが組み合わせて有効であることを検証できる制約を定義するのが難しくなります (日付を時間グラニュルの日、月、年で分割し、各パーツを別々の relvar に保存したと想像してください!)。

3) 個人識別子の場合、ファーストネームとラストネームの組み合わせが適切であることはめったにありません。識別子は通常、必要な信頼レベルに基づいて選択されます。雇用主は、参照、資格などを確認してから、給与参照を発行します。警察の申し出では道端で運転免許証を見る必要があるかもしれませんが、犯罪で有罪判決を受けた場合は指紋が取られます. DBMS は人物を確認できないため、自動インクリメント整数が適切であることはめったにありません。

于 2016-11-21T13:30:56.497 に答える