3

これは、データベースで 1 つのテーブルまたは 3 つのテーブルとして表す必要がありますか? 私と私の友人はこれについて異なる意見を持っているので、これについての一般的な見解を見たいと思います. (おそらく、どちらかのソリューションに投票する必要がありますか?)

Create Table Order
// Basic fields of the table
 - ID (Primary key)
 - CustomerID  (integer, with a FK)
 - Quantity
 - ProductID  (integer, with a FK)

 // Then depending on user selection, either these fields need to be specified 
 // (could be factored out to a separate table):
 {
 - InternalAccountID (integer, with a FK)
 - InternalCompanyID (integer, with a FK)
 }

 // Or these (could be factored out to a separate table):
 {
 - ExternalAccountNumber (free text string)
 - ExternalCompanyName (free text string)
 - ExtraInformation (free text string)
 }

1 テーブル アプローチ:

長所:

  • パフォーマンス (2 つではなく 1 つの挿入、FK チェック、結合なし)
  • おそらくスペースが少なくて済みます (追加のテーブルにはオーバーヘッド + インデックス + 追加の ID フィールドがあります)
  • 3 つではなく 1 つのテーブル
  • 2 + 3 フィールド (または何?) のためだけに新しいテーブルに分割することはほとんど正当化できません。

短所:

  • Null 可能フィールド
  • 潜在的に余分な「タイプ」列 (スキップ可能)
  • 3NFを突破(?)

賛否両論と個人的な意見をお願いします。:)

編集:実際に使用しているエンティティとは異なるエンティティを使用して例を単純化しようとしたため、モデルを変更するための提案はあまり役に立ちません。つまり、ドメイン モデルよりも技術的な側面に重点を置いてください。

4

7 に答える 7

3

私の意見は

 // Then depending on user selection, either these fields need to be specified 
 // (could be factored out to a separate table):
 {
 - InternalAccountID (integer, with a FK)
 - InternalCompanyID (integer, with a FK)
 }

 // Or these (could be factored out to a separate table):
 {
 - ExternalAccountNumber (free text string)
 - ExternalCompanyName (free text string)
 - ExtraInformation (free text string)
 }

順序は常に1:1であり(つまり、3つのaccountIDを持つことはできません)、それを1つのテーブルのままにします。nullの問題に対処するために、InternalCustomer(ブール値)またはCustomerType(varChar)という列をもう1つ追加して、内部または外部の顧客を定義し、2つのフィールドセットのどちらを調べる必要があるかを知ることができます。特定の顧客。

このデータまたはDB全体のスキーマの完全な使用法がわからないため、これに対する応答を完全に修飾することはできません。

于 2010-07-12T13:28:03.607 に答える
3

これが自明であることを願っています。

order_model_v1

于 2010-07-30T12:29:23.333 に答える
0

データの重複を避けたい場合は、2 つまたは 3 つのテーブル ソリューションを使用する必要があります。たとえばExternal、Order テーブルに列がある場合、値が複数回存在する可能性があります。データが次のようになっている場合:

ID   ExternalCompanyName
1    ACME
2    ACME
3    My Company
4    ACME

ここで、ACME が名前を ACME, Inc. に変更した場合、多くの行を更新する必要があります。外部企業が別のテーブルにあるテーブルが正規化されている場合は、1 つの行を更新します。口座番号を独自のテーブルに入れるという議論があるかもしれませんが、極端な正規化のためにそれを残します。

各会社/アカウントが 1 つの注文しか持てない場合を除き、注文と会社/アカウントの間に 1 対 1 の関係があるようには見えません。1 対多の関係のように聞こえます。

ここで、単一テーブル環境で ExternalCompanyName を更新するときにミスが発生し、一部の行のみが更新された場合はどうなるでしょうか。ACME を含む行と ACME, Inc. を含む行がいくつかあります。最終的にデータが不適切な状況になります。

また、これが実際に 1 対多の関係である場合、実際にはスペースを節約していません。データを別のテーブルに一度格納するのではなく、順番に複製しています。

于 2010-07-29T05:55:29.157 に答える
0

ボリュームが増加するにつれて、2 つのテーブルからの選択は 1 つよりもはるかに高速になる場合があります。この種のリファクタリング (パーティション) は、成熟したデータベースでパフォーマンスを向上させるために行われることがあります。

いくつかの基準がこのテーブルにあり、他の基準が異なるテーブルにある複数テーブルの結合にこれを使用することを想像してください。

select from order join customer using (customer_id)
where
    order.order_date between ? and ?
    and customer.name = ?

ディスクから日付のすべての行を取得しorder、結合に一致しないため、それらの多くを破棄することになる場合があります。このディスクからのフェッチは遅く、RAM キャッシュを損なう可能性があります。

select from order join order_detail using (order_id) join customer using (customer_id)
where
    order.order_date between ? and ?
    and customer.name = ?

この場合、orderディスクからすべての行をロードするとき、テーブルが狭くて小さいため、以前ほどひどくはなりません。フィルタリングに関係のない長いフィールドをすべてロードする必要はありません。最終的に、 に結合した後、すべての基準に一致customerする行のみがフェッチされます。order_detail

これが大きくなると予想される場合は、検索に最も重要なフィールドが 1 つのテーブルにあり、「データ」フィールドが他の 1 対 1 テーブルにあるように、テーブルを分割することを検討する必要があります。

要点は次のとおりです:通常の形式とドメインは 1 つのことですが、パフォーマンスには多くの場合トレードオフが必要です。それらの一部を非表示にすることはできますが (分割をビューでカバーします)、すべてを非表示にすることはできません (選択を高速化するためにフィールドを複製/集約します)。

于 2010-07-29T06:21:06.440 に答える
0

私は純粋主義者ではないので、理にかなっている場合は 3nf が適していますが、常にそうなることを当然と考える必要はありません。

実用的な観点から、あなたの目標は何ですか? あなたの賛否両論のリストは良いスタートです。リストにさらにいくつかのアイデアを追加したいと思います。

1)データベース内の他のテーブルをこのデータに関連付ける (結合するなど) 必要がありますか? それがRDBのポイントのようなものです。

2) データベースは拡張されますか? 今は 1 つのテーブルが理にかなっているとしても、それは常に理にかなっていますか? さらにテーブルを追加したいと思っていて、正規化されていないテーブルのために余分な行が返されたり、実行時間が遅くなったりするなどの「回避策」を余儀なくされている場合は、後悔するでしょう。

3) 顧客が新しい外部アカウントを取得するとどうなるか、またはあなたはどうなるか。まったく新しいレコードを作成しますか? 「お客さまの口座番号は?」などの質問にどう答えるか。

...

一般的に、私はスケーラブルで、この場合は 3nf を意味すると思います。1 つのテーブルは非常に狭い範囲で処理するのが簡単ですが、何か変更があった場合は、「作成されたすべての依存関係を台無しにすることなく、このテーブルを適切に関連する 3nf テーブルに分割するにはどうすればよいか」に対処する必要があります。それ?"。そいつは面白くない。

于 2010-08-02T22:45:51.640 に答える
0

私は絶対に 3 テーブル ソリューションを使用しません。このデータを 3 つのテーブルに分割することで、外部キーと結合せずにクエリで完全な注文ヘッダーを返すことはできず新しい注文を挿入するたびに複数のテーブルとインデックスが更新されます。これは同時実行の問題です。InternalOrders 用と ExternalOrders 用の 2 つのテーブルを使用することをお勧めします。両方の注文セットからのデータの統合クエリが必要な場合は、両方のテーブルを結合したビューを定義します。

注文ヘッダーの一部として製品 ID と数量が表示されていることに驚きまし。私がこれまでに見たすべての注文追跡データベースは、注文 ID を外部キーとして使用して、注文項目を個別のテーブルとして分割するため、1 つの注文に複数の製品 (または、さまざまな数量、配達時間などを持つ同じ製品) を含めることができます。 )。

于 2010-07-31T05:11:32.003 に答える
0

アカウント情報は、顧客が注文する前に関連付けられていますか (つまり、指定された CustomerID が使用できるアカウント ID を追跡する別のテーブルがあります)? 1 つのユニバーサル AccountId (代理キー) があり、アカウントのテーブルに 3 つの varchar フィールドと、アカウントの種類を追跡する 1 つ (使用される請求など)?

それができる場合、注文は (エンティティとして) 使用された支払い方法を実際には気にしないため、注文は 1 つの AccountID のみを追跡します。他のすべては、いわば他人のビジネスであり (請求または資金のチェックなど)、そのエンティティとその処理には、とにかくより多くのデータが必要になります。

これにより、注文がクリーンで null のない状態に保たれ、懸念事項の分離も容易になります。

概念的には、注文は実際にはいわゆるファクト テーブルです。数値と FK のみを保持し、アイテムのサイズは小さいですが、それらの数は膨大です。

そう:

 Table Order (
     - OrderId
     - Quantity
     - ProductId
     - DiscountId -- sonner or latter :-)
     - AccountId
     - PaymentStatus -- probaly FK as well or predefined constant
 )

 Table Account (
     - AccountId
     - BillingInfo  -- akka ext acct number as text
     - PrincialName -- akka ext company name, some equivalent for internal acct-s
     - AdditionalData
 )
于 2010-08-03T09:12:06.477 に答える