16

私はこれが頻繁に出てくることに気づきましたが、それにアプローチする最善の方法がわかりません。

私が抱えている問題は、ルックアップ テーブルに外部キーを使用するか、それを要求するテーブルで直接ルックアップ テーブルの値を使用して、ルックアップ テーブルの関係を完全に回避するかを決定する方法です。

注意点:

  • 2 番目の方法では、ルックアップ テーブルでデータが変更された場合、データを参照するすべてのレコードを一括更新する必要があります。

  • これは、多数のルックアップ テーブルを参照する多数の列を持つテーブルに重点を置いています。したがって、多数の外部キーは、テーブルをクエリするたびに多数の結合を意味します。

  • このデータは、ルックアップ テーブルから取得されるドロップ ダウン リストから取得されます。リロード時にデータを一致させるには、値が既存のリストにある必要があります (最初のポイントに関連する)。

ここでのベスト プラクティス、または考慮すべき重要なポイントはありますか?

4

7 に答える 7

29

VARCHAR 主キーを持つルックアップ テーブルを使用でき、メイン データ テーブルはその列で FOREIGN KEY を使用し、カスケード更新を行います。

CREATE TABLE ColorLookup (
  color VARCHAR(20) PRIMARY KEY
);

CREATE TABLE ItemsWithColors (
  ...other columns...,
  color VARCHAR(20),
  FOREIGN KEY (color) REFERENCES ColorLookup(color)
    ON UPDATE CASCADE ON DELETE SET NULL
);

このソリューションには、次の利点があります。

  • ルックアップ テーブルへの結合を必要とせずに、メイン データ テーブルの色名をクエリできます。
  • ただし、色名はルックアップ テーブル内の色のセットに制限されます。
  • ルックアップ テーブルにクエリを実行することで、一意の色名のリストを取得できます (メイン データで現在使用されているものがない場合でも)。
  • ルックアップ テーブルの色を変更すると、その変更はメイン データ テーブル内のすべての参照行に自動的に反映されます。

このスレッドの他の非常に多くの人々が、「正規化」とは何かについて間違った考えを持っているように見えることは、私にとって驚くべきことです。代理キー (どこにでもある「id」) の使用は、正規化とは何の関係もありません!


@MacGruber からの再コメント:

はい、サイズは要因です。たとえば InnoDB では、すべてのセカンダリ インデックスは、特定のインデックス値が発生する行の主キー値を格納します。したがって、セカンダリ インデックスが多いほど、主キーに「かさばる」データ型を使用するためのオーバーヘッドが大きくなります。

また、これは外部キーにも影響します。外部キー列は、参照する主キーと同じデータ型である必要があります。小さなルックアップ テーブルがある場合は、50 行のテーブルの主キーのサイズは問題ではないと考えます。しかし、そのルックアップ テーブルは、他のテーブルの数百万または数十億の行によって参照される可能性があります。

すべての場合に正しい答えはありません。さまざまなケースで、どの答えも正しい可能性があります。トレードオフについて学び、ケースバイケースで情報に基づいた決定を下すようにしてください。

于 2008-12-20T20:00:28.150 に答える
5

単純な原子値の場合、主に複雑さの面で、この一般的な知恵に同意しない傾向があります。帽子を含むテーブルを考えてみましょう。「非正規化」の方法を実行できます。

CREATE TABLE Hat (
  hat_id INT NOT NULL PRIMARY KEY,
  brand VARCHAR(255) NOT NULL,
  size INT NOT NULL,
  color VARCHAR(30) NOT NULL /* color is a string, like "Red", "Blue" */
)

または、「カラー」テーブルを作成して、さらに正規化することもできます。

CREATE TABLE Color (
  color_id INT NOT NULL PRIMARY KEY,
  color_name VARCHAR(30) NOT NULL
)

CREATE TABLE Hat (
  hat_id INT NOT NULL PRIMARY KEY,
  brand VARCHAR(255) NOT NULL,
  size INT NOT NULL,
  color_id INT NOT NULL REFERENCES Color(color_id)
)

後者の最終結果は、次の代わりに、いくつかの複雑さを追加したことです。

SELECT * FROM Hat

あなたは今、言わなければなりません:

SELECT * FROM Hat H INNER JOIN Color C ON H.color_id = C.color_id

その余分な参加は大したことですか?いいえ - 実際、それはリレーショナル デザイン モデルの基礎です - 正規化により、データの不整合の可能性を防ぐことができます。しかし、このような状況はすべて少し複雑になります。正当な理由がない限り、なぜそうしているのかを尋ねる価値があります。考えられる「正当な理由」には、次のものが含まれると考えています。

  • この属性に「ぶら下がっている」他の属性はありますか? たとえば、16 進数値が常に色名に依存するように、「色名」と「16 進数値」の両方をキャプチャしていますか? その場合、1 つの行に ("Red", "#FF0000") があり、別の行に ("Red", "#FF3333") があるという状況を防ぐために、別のカラー テーブルが必要になることは間違いありません。複数の相関属性は、エンティティを正規化する必要があることを示す最大のシグナルです。
  • 可能な値のセットは頻繁に変更されますか? 正規化されたルックアップ テーブルを使用すると、単一の行を更新するだけなので、セットの要素に対する将来の変更が容易になります。ただし、頻度が低い場合は、代わりにメイン テーブルの多数の行を更新する必要があるステートメントをためらわないでください。データベースはそれが得意です。よくわからない場合は、速度テストを行ってください。
  • 可能な値のセットは、ユーザーによって直接管理されますか? つまり、リスト内の要素を追加/削除/並べ替えできる画面はありますか? もしそうなら、明らかに別のテーブルが必要です。
  • 個別の値のリストは、UI 要素に影響を与えますか? たとえば、「色」は UI のドロップリストですか? そうすれば、ドロップリストを表示する必要があるたびにテーブルで SELECT DISTINCT を実行するよりも、それを独自のテーブルに置くほうがよいでしょう。

それらのどれにも当てはまらない場合、正規化する別の (正当な) 理由を見つけるのは難しいでしょう。値が特定の (小さい) 正当な値のセットの 1 つであることを確認したいだけの場合は、値が特定のリストにある必要があることを示す CONSTRAINT を使用することをお勧めします。必要に応じて、後で別のテーブルにいつでも「アップグレード」できます。

于 2008-12-20T15:46:36.167 に答える
3

誰も考慮していないことの 1 つは、ルックアップ テーブル内のデータが時間の経過とともに変化する可能性があり、結合されたレコードが履歴である場合、ルックアップ テーブルに結合しないということです。例は部品表と注文表です。ベンダーは部品を削除したり、部品番号を変更したりすることがありますが、注文テーブルには、注文された時点で注文されたものとまったく同じものが含まれている必要があります。したがって、レコードの挿入を行うためにデータをルックアップする必要がありますが、ルックアップ テーブルに結合して既存の注文に関する情報を取得することは決してありません。代わりに、部品番号、説明、価格などを注文テーブルに格納する必要があります。これは、価格の変化が履歴データに反映されず、財務記録が不正確にならないようにするために特に重要です。この場合、あらゆる種類のカスケード更新も使用しないようにする必要があります。

于 2008-12-22T22:00:38.580 に答える
2

rauhr.myopenid.comは次のように書いています。

この問題を解決するために決定した方法は、第 4 正規形を使用することです。...

それは第 4 正規形ではありません。これは、One True Lookup と呼ばれるよくある間違いです: http://www.dbazine.com/ofinterest/oi-articles/celko22

第 4 正規形: http://en.wikipedia.org/wiki/Fourth_normal_form

于 2008-12-20T20:42:10.797 に答える
1

他の誰もあなたの2番目のポイントに対処していないので:クエリが長くなり、それらすべての結合のために読み取りと書き込みが困難になると、通常、ビューはそれを解決します。

于 2008-12-20T08:13:11.120 に答える
1

ビューにルックアップを取得させることで、常にビューに対してプログラムすることをルールにすることもできます。

これにより、ビューを最適化し、コードをテーブルの変更に耐えられるようにすることができます。

オラクルでは、必要に応じてビューをマテリアライズドビューに変換することもできます。

于 2008-12-20T08:28:39.297 に答える
1

正規化は、データベースのベスト プラクティスの一部として広く認識されています。正規化では、データをプッシュしてキーで参照します。

于 2008-12-20T06:45:33.933 に答える