1

クライアント固有のアイテムをリンクするために使用される次のテーブルについて、誰かと話し合っています。

Table LINK:

Client (int) 
Item1 (int) 
Item2 (int)

これは論争のあるデザインです。3つのフィールドはすべて、他のテーブルを参照します。2つのItemフィールドは、同じ他のテーブルを参照します。これらは実際のフィールド名ではないため、命名規則については気にしないでください(ただし、「1」と「2」は実際にはフィールド名の一部です)。私は、この設計は1NF違反の理由で悪いと主張していますが、他の人は、これは不快に思えますが、他のすべてのオプションは、特定のユースケースでは悪いと主張しています。

ノート:

  • ほとんどの場合、2つのアイテムを相互にリンクするだけで済みます。
  • ただし、N:1グループは許可されます。このような場合、同じItem1がItem2の値が異なる複数の行で繰り返されます。
  • 一部のItem2値(既存のItem1-Item2リンク内)自体が他のItemにリンクされている場合も非常に少なく、これらの場合、これらの値はItem1列にあり、他のリンクされた値はItem2列にあります。 ; リンクされたすべてのアイテムは1つのグループに対応するため、そのように取得する必要があります。

私の主張:

  • これは1NFに違反します。Item1とItem2は同じテーブルの外部キーであるため、繰り返しグループを構成します(相手は繰り返しグループの定義に同意しません)。
  • Itemの検索の場合、これは、たとえばGroupIDフィールドを代わりに使用するテーブルでは、1つではなく2つのインデックスが必要であることを意味します。
  • これにより、制限句はItem1フィールドとItem2フィールドの両方を調べる必要があるため、このテーブルで特定のアイテムを検索するクエリはより複雑になります。
  • アイテムリンクのチェーンが発生する場合の取得は、より複雑になります。

反対側は主張します:

  • 最も実行可能な代替案は、単一のItemフィールドと追加のGroupIDフィールドを持つテーブルです。
  • より単純で、より一般的な2項目のリンクの場合は、より複雑になります。
  • GroupIDスロットの取得に同時実行の問題がある可能性があり、それを管理する必要があります
  • GroupIDの同時実行性の問題を管理するには、一意性の制約があるフィールドにGroupIDを含む2番目のテーブルが必要になる可能性があります
  • 特にORMが使用されている場合は、少なくとも一部の時間は結合を実行する必要があります。結合は、現在の設計のように単一のテーブルを使用するよりも効率的ではありません。

これについていくつか意見を聞きたいと思います。私はデータベース設計、特に1NFに関するSOに関する他の投稿を読みましたが、それらは私が望んでいたように上記の私のケースを具体的に扱っていません。また、オンラインでの多くの調査に基づいて、1NFのようないわゆる標準は、さまざまな人々によってさまざまな方法で定義できることも理解するようになりました。私は両方の議論について可能な限り明確にし、どちらか一方にバイアスをかけないように努めました。

編集1:

  • Item1とItem2は(金融)取引です
  • 「1」と「2」は実際にはフィールド名の一部です
4

2 に答える 2

2

Item1 と Item2 とは何ですか? それらは別個のエンティティですか?それからデザインは私には良いようです。

たとえば、巡回セールスマン問題の解決策をデータベースに入力するとします。テーブル City(cityId, latitude, longitude) とテーブル Path(pathId, salesmanId) があります。ここで、セールスマンが n+1 都市を訪問するパスは、PathSegment(pathId、segmentId、fromCityId、toCityId) の n エントリで表されます。ここで、fromCityId と toCityId は同じテーブル City を参照する外部キーですが、PathSegment エンティティの異なる属性を記述しているため、NF1 には違反しません。

編集:

ツリーを保存したいのですが、実際には、ツリーだけがほとんどリンクされたリストであり、それらのほとんどは 2 つのノードしかないリンクされたリストですよね? どうやらあなたの同僚は隣接リストとしてこれをしたいので、次のようなツリー

1-2-3
\-4

になる

(1,2)
(2,3)
(1,4)

それは何も悪いことではありませんが、ツリーをデータベースに格納する唯一の方法ではありません。代替案の概要については、こちらを参照してください

あなたの場合、隣接リストを使用する利点は、ほとんどのツリーにノードが 2 つしかないため、それらのほとんどがテーブル内の 1 つの行になり、シンプルに保たれることです。また、すぐ隣人に関する質問も簡単です。「この支払いの請求書は何ですか?」になる

select item1 from link where item2 = :paymentID

これもきちんとしています。ただし、欠点もあります。子ノードの順序はしばしば重要であり、リストはここでは役に立たないため、別の列として、または外部キーが参照しているテーブルのタイムスタンプのようなものとして保存する必要があります)。また、ブランチ全体の再構築は再帰的なタスクになり、すべてのデータベース システムがそれを実行できるわけではありません。そのため、アプリケーションがメッセージ ボードのような請求履歴の概要を頻繁に取得する必要がある場合は、隣接するノードのリストをクライアント上でツリーに変換して処理するアプリケーション側のロジックが必要になる場合があります。それが面倒になる場合は、ネストされたセットの表現を検討することをお勧めします。ここを参照してください

あなたの問題に最適なものは何ですか?いくつかの要素に依存します: ツリーのサイズと形状 (ほとんどが短いリンク リストである場合は、隣接リストが適しています)、挿入と更新の頻度 (頻繁な場合は、挿入が安価であるため、隣接リストが適しています)、頻度とクエリの複雑さ (頻繁で複雑な場合は、選択が単純で高速なため、ネストされたセットが適しています)。したがって、メッセージ ボードの場合は、ネストされたセット (または速度と追加のクールさのためにトロパシュコのネストされた間隔) を使用しますが、単純な要求応答 (場合によってはさらに応答) テーブルの場合は、おそらく隣接リストを使用します。 .

于 2009-12-01T15:22:59.920 に答える
1

同じテーブルを指す 2 つの外部キーを持つことは、既定では "違反" ではありません。Person テーブルに、FatherID フィールドと MotherID フィールドの両方が Person テーブルを指している場合があります。これらは意味的に異なる属性であるため、これは繰り返しグループではありません。あなたの最初の主張は、書かれており、他の文脈から解放されているため、誤りです。

于 2009-12-01T16:01:20.840 に答える