web-dev-qa-db-ja.com

CSV列を別のテーブルに分割する(1NFを強制する)ことで、不要な複雑化はありませんか?

複数のテーブルにCSV列を作成することを選択した理由をテーブル設計者に非常に注意深く尋ねました。

設計者の答えは、CSV列を個別のテーブルに分割することは「不必要に複雑」だったということです。

1つのCSV列が暗黙的な結合で使用され、CSV列の複数の値の値が使用された回数をカウントします。

2つのテーブルをバインドするwhere原因はlike % | table_b.csv_column | %操作を使用します。

私は読んで、正当な理由がない限り、正規化は必ずしも必要ではないことを学びました。
しかし、正規化しないことの正当な理由が何であるかはわかりません。

これは(「複雑さ」を回避する)最初の正規形(1NF)を適用しないことの正当な理由ですか?

表:TB_DISASTER_CAUSE_CATE

CATEGORY_ID   CATEGORY_N CATEGORY_L L
------------- ---------- ---------- -
DC006001002   ****                3 Y
DC006001003   ****                3 Y
DC006002001   ****                3 Y
DC007001001   ****                3 Y
DC007002001   ****                3 Y
DC007002002   ****                3 Y
DC007003001   ****                3 Y
DC007003002   ****                3 Y
DC007003003   ****                3 Y

表:TB_DISASTER_HISTORY

SEQ DISASTER_TYPE DISASTER_CAUSE                                             
----- ------------- ------------------------------------------------------------
   32 DT001003002   DC001001004|DC002001002|DC003001001|DC007002001             
   33 DT002003007   DC001001004|DC007002001                                     
   34 DT002003009   DC001001003|DC003001002|DC007002001                         
   16 DT002003001   DC001001004|DC002001002|DC005001003|DC007002001             
   17 DT002003001   DC001001004|DC002001002|DC005001003|DC006001003|DC007002001 
   18 DT002003007   DC001001003|DC001002002|DC002001001|DC002002002|DC004001001|
                    DC007002001                                                 

   19 DT002003007   DC001001003|DC001001004|DC003001002|DC007002001             
   20 DT002003007   DC001001003|DC001001004|DC007002001                         
   21 DT002003007   DC001001003|DC003004001|DC007002001                         

  SEQ DISASTER_TYPE DISASTER_CAUSE                                             
----- ------------- ------------------------------------------------------------
   22 DT002003007   DC001001003|DC001001004|DC002001002|DC007002001  

[〜#〜]クエリ[〜#〜]

select 
          x.category_id as category_id
          ,x.cnt as ccnt
          ,y.category_nm as category_nm
        from(

        select category_id , count(*) cnt from 
            TB_DISASTER_CAUSE_CATE  a , 
            tb_disaster_history b 

           where last_yn  = 'Y'
             and b.disaster_cause like '%'||a.category_id||'%'
             and b.disaster_type=#disaster_type#
         group by category_id  ) x

         inner join (
         select * from tb_disaster_cause_cate
         where last_yn='Y') y
         on x.category_id = y.category_id;
5
Ascendant

この質問への回答は、これへの回答と同じです 質問 。どちらも本当に第1正規形(1NF)についてです。リンクされた質問は、ダッシュ「-」を介して連結されたさまざまなデータ要素で構成されるキー列の正当化に関係していました。この質問は、パイプ "|"を介して含まれる同じデータ要素の異なるで構成される非キー列の正当化に関係しています。回答するには、最初にifそのような設計を評価する必要があります1NFの意図に違反します。もしそうであれば、1NFの違反をすることが正当化されるのはいつですか。

バックグラウンド

最初に、1NFの構成を簡単にまとめます。テーブルはRelational(R-Table)テーブルであり、したがって、その設計において以下を保証する規律に従う場合、正規化されます(定義により1NFを意味します)。

  • 明確で順序付けされていない行
  • 一意の名前が付けられた、順序付けされていない列
  • 各列には、対応するドメインからの単一の値が含まれます

要件3は、列に欠落値(またはNULLマーカー)を含めることができないことを意味します。ここでは、要件1と2、および要件3の「欠落値なし」の部分が満たされていると仮定します。テーブルのすべての行を確認して、欠損値、重複行、および列または行の順序でエンコードされた暗黙的な情報がないことを確認しないと、コンプライアンスを実際に評価できないため、「仮定」と言います。ここで、schema概念モデルから保証行の重複や欠損値がないことまでのビジネスルールを実装する整合性制約を含みます。DBMSを知っているので、これらの要件に関するコンプライアンスを検証するためにすべてのデータを調べる必要はありません。 everyケースでこれらのルールとの一貫性を強制します。ただし、すべてのデータを調べる必要がありますが、追加情報を暗黙的にエンコードするために行または列の順序付けが使用されていないことを確認します。

上記の仮定を踏まえ、パイプで区切られた単一の列への複数の災害原因コードの配置が単一の値の列の要件3に違反しているかどうかを判断するために残しました。ダッシュで区切られた複数のデータ要素を持つキー列に関する前の質問への私の回答では、そのようなデザインに違反しており、どのような状況でも正当化されることはないと述べました。私の回答は、 Fabian Pascal および Chris Date からの1NFに関する最新かつ決定的な考え方(回答の最後に提供する参照)。Fabian自身がその質問への回答に貢献した彼は私の答えを修正しました彼は私の主張が厳しすぎると言いました:

組み合わせが視覚的な目的のみであり、保証である場合、DBMSは常に単一の値(ここで強調する)としてアクセスされます。問題はそのような保証は不安定です。

ファビアンの訂正は、単一値の列要件の微妙な点の中心にあります。その列のドメインが関係値ドメイン(RVD)であり、このようにその列に単一のテーブルが含まれている場合、それはではないは1NFの違反です。今正当化する機能で喜ぶ前にダッシュやパイプなどで区切られた複数のデータ要素を含む列を作成する際の「上級」開発者の慣例として、SQL DBMSが実際にRVDをサポートしていないため、列を単一の値として操作することが困難であることを最初に指摘しておきます。第2に、DateとPascalの両方が、RVDは1NFの違反ではないが、追加の利点なしに(いくつかの極端な状況を除いて)追加の複雑さと非対称性をもたらすことを指摘しています。したがって、それは許容できるかもしれませんが、詳細については、参考文献を参照してください。

デザインの評価

1NFの背景が整ったところで、この状況に取り掛かりましょう。問題の列、災害の原因、私は提出するだろう単一の値の列は正確にではないは、より大きな文字列内の個々の値がにアクセスするクエリの例を与えるため、テーブルは正規化されていません。これは、正規化された設計が2テーブルを必要とするため、「不必要に複雑である」と認識されるため、RテーブルではなくnotRテーブルになるようにテーブルを設計することは依然として正当化されます。 ? "と言います2つの理由で絶対にではありません。最初に、アインシュタインは物事は可能な限り単純でなければならないが単純ではないことを述べました。この非正規化設計は、はR-Tableではありません。R-Tableの利点はどれも得られません。この点については参照で詳しく説明しますが、主なポイントは、各データ要素への論理アクセスの保証が失われることです。より微妙な問題は、災害原因の完全性を維持することははるかに困難です。災害原因が子テーブル。各災害原因コードは、災害ごとに1度だけ割り当てられることを保証し、キー制約によって保証されます。災害履歴テーブルの複数値列として、アプリケーションは同じ原因コードを誤って2回連結する可能性があります。多値列にこの制約を実装するために必要な手続き型トリガーの記述方法を考えていると、頭が痛くなります。最後に、私は論理設計のみを取り上げたことに注意してください。さまざまなSQL DBMSの物理的な実装には、提供されるクエリのように、実行されるクエリの結果として生じる最適化に夢中になる専門家がたくさんいると思います。 、このデータにアクセスします。

最後に、2つのテーブルを持つ正規化されたデザインが「不必要に複雑」であるという根拠さえも間違っていると私は主張します。代わりに、単一のテーブルの複数値列は「不必要に複雑」であると私は考えています。提供されたクエリは、特定の災害原因が災害に寄与した回数を数えようとしていますが、作成設計に単純に災害テーブルと子災害がある場合よりも作成が複雑です原因テーブル。ネストは不要であり、結合はその目的に関して単純で明白です。スキーマを初めて見た人は、データを見なくても、災害に関する情報と各災害について簡単に理解できます。複数値の列を使用すると、この単純な構造が不明瞭になり、初めてユーザーがデータ値を調べて、実際には災害が多くの原因を持つ可能性があることを発見する必要があります。

参考文献

ファビアンパスカルの 実用的なデータベース基盤シリーズ 。論文#5は1NFとRVDを扱います。すべてのペーパーを購入する場合(それらはすべてのファンダメンタルズに対応する補足セットであるため、実際に購入する必要があります)、1NFに具体的に対処する2つの追加のペーパーを入手できます-CJ日付による「最初の正規形は本当に意味する」および「最初の正規形」フォームは意味しない」ファビアンパスカルによって。次に、CJ Dateはリレーショナル理論について幅広く書いています。正規化に関する最新のリファレンスは データベース設計とリレーショナル理論:正規形とすべてのジャズ です。最後に、Fabian Pascalは 最近1NFについてブログに書いた を持っており、それらのブログは優れた読書です。

7
Todd Everett