web-dev-qa-db-ja.com

ルックアップテーブルの適切な使用

データベースでルックアップテーブルをいつどこで使用するかについて、適切な境界をどのように配置するかを正確に理解するのに苦労しています。私が見たほとんどの情報源は、私はあまり多くすることは決してできないと言っていますが、ある時点で、データベースは非常に多くの断片に分解され、効率的ではあるが管理できなくなるようです。これが私が一緒に取り組んでいるもののまとめられた例です:

従業員というテーブルがあるとします。

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

少しの間、データがより複雑で数百の行を含んでいると仮定します。ルックアップテーブルに移動できる最も明白なことは、位置です。 Positionsというテーブルを作成し、Positionsテーブルの外部キーを、Position列のEmployeesテーブルに貼り付けます。

ID  Position
1   Manager
2   Sales

しかし、情報が管理不能になる前に、情報をより小さなルックアップテーブルにどれだけ分解し続けることができるでしょうか。性別テーブルを作成し、1を男性に対応させ、2を別のルックアップテーブルの女性に対応させることができます。 LNameとFNameをテーブルに入れることもできました。すべての "John"エントリは、ID 1がJohnに対応することを示すFNameテーブルを指す1の外部キーに置き換えられます。ただし、このウサギの穴をこのようにあまりにも遠くまで進んだ場合、Employeesテーブルは混乱した外部キ​​ーに削減されます。

ID  LName   FName   Gender  Position
1   1       1       1       1
2   1       2       2       2
3   2       1       1       2

これはサーバーで処理する方が効率的である場合とそうでない場合がありますが、これを維持しようとする通常の人には確かに読めないため、アプリケーション開発者がサーバーにアクセスしようとするとさらに困難になります。だから、私の本当の質問は、どこまで遠いのですか?この種のものの「ベストプラクティス」または優れたガイドラインのセットはどこかにありますか?私が抱えているこの特定の問題について、使いやすく優れた一連のガイドラインを本当に明らかにする情報をオンラインで見つけることはできません。データベース設計は私にとっては古き良き帽子ですが、良いデータベース設計は非常に新しいため、過度に技術的な答えが頭に浮かぶかもしれません。何か助けていただければ幸いです!

25
Brad Turner

しかし、情報が管理不能になる前に、情報をより小さなルックアップテーブルにどれだけ分解し続けることができるでしょうか。別のルックアップテーブルで、性別テーブルを作成し、1を男性に、2を女性に対応させることができます。

2つの異なる問題が混在しています。 1つの問題は、「ルックアップ」テーブルの使用です。もう1つは、代理キー(ID番号)の使用です。

この表から始めます。

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

このようなポジションの「ルックアップ」テーブルを作成できます。

create table positions (
  pos_name varchar(10) primary key
);

insert into positions
select distinct position 
from employees;

alter table employees
add constraint emp_fk1
foreign key (position) 
  references positions (pos_name);

元のテーブルは、「ルックアップ」テーブルを作成する前とまったく同じように見えます。そして、従業員のテーブルは、そこから有用で人間が読めるデータを取得するためにno追加の結合を必要とします。

「ルックアップ」テーブルを使用すると、次のようになります。アプリケーションでは、外部キー参照が提供する入力値を制御する必要がありますか?その場合は、常に「ルックアップ」テーブルを使用できます。 (サロゲートキーを使用するかどうかに関係なく)。

場合によっては、設計時にそのテーブルを完全に設定できることがあります。他の場合では、ユーザーは実行時にそのテーブルに行を追加できる必要があります。 (そして、新しいデータを確認するには、おそらくいくつかの管理プロセスを含める必要があります。)実際には ISO標準 を持っている性別は、設計時に完全に入力できます。国際的なオンライン製品注文のストリート名は、おそらく実行時に追加する必要があります。

あなたのEmployeesテーブルでは、「Position」のルックアップしかありません。これは、展開できるデータのセットが限られているためです。

  • 性別は自己記述型(たとえばMまたはF)で、値は2つに制限されており、CHECK制約で強制できます。新しい性別を追加しません(政治的正しさを無視して)
  • ファーストネーム「ジョン」は、制限された制限付きのデータセットの一部ではありません。潜在的なデータセットは、事実上無制限になるほど大量であるため、ルックアップであってはなりません。

新しい位置を追加したい場合は、ルックアップテーブルに行を追加するだけです。これにより、正規化の1つのポイントである データ変更異常 も削除されます

また、従業員が100万人になると、varcharよりもtinyint PositionIDを保存する方が効率的です。

新しい列「給与通貨」を追加しましょう。ここでは、CHF、GBP、EUR、USDなどのキーを持つルックアップテーブルを使用します。代理キーは使用しません。これは、性別などのCHECK制約で制限される可能性がありますが、位置などの限られた拡張可能なデータのセットです。 tinyintではなくchar(3)であるにもかかわらず、従業員データの100万行に表示される場合でも自然キーを使用するため、この例を示します

要約すると、ルックアップテーブルを使用します

  1. 列に有限でありながら拡張可能なセットデータがある場合
  2. 自己説明はどこですか
  3. 回避するには データ変更の異常
8
gbn

答えは「状況次第」です。あまり満足できるものではありませんが、デザインを押したり引いたりする影響はたくさんあります。データベースを設計するアプリプログラマーがいる場合、ORMは複雑さを隠すので、説明したような構造が機能します。レポートを作成し、アドレスを取得するために10個のテーブルを結合する必要がある場合は、髪の毛を抜く必要があります。

使用、意図された使用、そしておそらく将来の使用のための設計。ここで、ビジネスプロセスに関する知識を得ることができます。獣医ビジネス用のデータベースを設計している場合、ハイテクな新興企業とはかなり異なる、機能のサイズ、使用方法、および方向性について合理的な前提があります。

お気に入りの引用を再利用するには

"賢い人はかつて「それが痛くなるまで正規化し、それが機能するまで非正規化する」と言った。

どこかにスイートスポットがあります。私の経験では、複数のテーブルにキーIDがあることは、主キーを変更しない場合に考えるほど深刻な犯罪ではありません。

実際のシステムからの高度に正規化されたテーブルのこの省略された例を取る

CREATE TABLE PROPERTY
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_TYPE
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_LOCALE 
PROPERTY_ID                  NUMBER(9)           NOT NULL,
(LOCALE_ID                   NUMBER(9)           NOT NULL,  --language 
VALUE                        VARCHAR2(200)       NOT NULL);

CREATE TABLE PROPERTY_DEPENDENCY
(PROPERTY_ID                 NUMBER(9)           NOT NULL,
 PARENT_PROPERTY_ID          NUMBER(9)                   ,
 PROPERTY_TYPE_ID            NUMBER(9)           NOT NULL);

これらのテーブルは、単一プロパティと親子プロパティのリンクリストを設定し、ここで使用されます

  CREATE TABLE CASE_PROPERTY
  (ID                        NUMBER(9)           NOT NULL,
  PARENT_ID                  NUMBER(9),
  CASE_ID                    NUMBER(9)           NOT NULL,
  PROPERTY_ID                NUMBER(9),
  PROPERTY_TYPE_ID           NUMBER(9)           NOT NULL);

これはうまく見えます:1回の選択でproperty_idを持つすべてのケースを取得します

選択するリストを取得しましょう

 Select pl.value, pd.property_id
 from property_locale pl, property_dependency pd
 where pl.property_id = pd.property_id
 and pd.property_type_id = 2;  --example number

次に、property_typeが3と4と5であるかどうかにかかわらず、ケースのすべてのプロパティを選択してみてください...

SELECT   cp2.case_id,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 2
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE1,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 34
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE2,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 4
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE3
  FROM   case_property cp2
 WHERE   cp2.case_id = 10293  

これはちょうど痛い...あなたがこれに対処するよりエレガントな方法を使用するときでさえ。ただし、ケースに1つのproperty_idのみが含まれるプロパティを分割することにより、正規化を少し追加します。これははるかに優れている可能性があります。

テーブルの数が多すぎるか、不十分であるかを調べるには、アプリケーションに質問してデータベースにクエリを実行し、レポートと年次分析を使用します。

5
kevinsky