web-dev-qa-db-ja.com

Ordersテーブルの適切な正規化-分割するかしないか

各注文には固有のSalesOrderNumberがあります。注文はさまざまなPartID番号で構成され、それぞれにOrderQuantity番号が関連付けられています。

現在、モデルには次の表があります。

Order table

このテーブルを次のように2つのテーブルに分割する必要があるかどうか疑問に思っています。

Order table with OrderDetail

これにより、OrderテーブルにはSalesOrderNumberごとに1行のみが残りますが、これが正規化の観点から必要かどうかはわかりません。どちらの取り決めも2NFを満たすべきだと思われます。 3NFとBCNFについてはまだ少し不安定です。

テーブルのサンプルは次のようになります。12345のSalesOrderNumberに関連する列のみが表示されます。

SalesOrderNumber PartID OrderQuantity 
12345            1a     1 
12345            2b     2 
12345            3c     43 
3

正規化の目的は、更新の異常を取り除くことです。具体的には、単一のファクトを変更すると、1行の1列のみが変更されます。たとえば、ShippingDestinationが変更された場合、これが提案された設計にどのように適用されるかを検討してください。

最初の設計では、1つのSalesOrderNumberに複数の行があり、それぞれに独自のPartIDがあるため、複数の行が変更される可能性があります。 2番目のデザインでは、単一の行のみが更新されます。したがって、2番目の設計はより正規化されています。

別の観点から、依存関係-どの値が一斉に変化するかを確認できます。最初の設計では、ある行から同じSalesOrderNumberを持つ別の行に移動すると、ShippingDestinationはDueDateと同じになります。ただし、OrderQuantityはこれら2つの行の間で異なります。したがって、OrderQuantityは、SalesOrderNumberだけではなく、PartIDについても知る必要があります。 2つの異なる依存関係があるため、2つの異なる正規化されたテーブル。 (機能的な依存関係/依存関係の分解には他にもありますが、それがその要点です。)

2NFは「パーツキーの依存関係」について話します。キーのすべての列がすべての非キー列の値を決定するために必要かどうか。最初の設計を見ると、(SalesOrderNumber、PartID)の複合キーがあります。特定のSalesOrderNumberを持つ1つの行から同じ番号を持つ次の行に移動すると、一部の列(たとえば、ShippingDestination)は常に同じになります定義により。 PartIDはキーにありますが、ShippingDestinationの値を決定するために必要ではありません。したがって、最初の設計は2NFではありません。

3NFは、「推移的な依存関係」-キーが変更されたため、または別の非キー列の値が変更されたために列の値が変更されたかどうかについて話します。 2番目の設計が3NFであるかどうかを示す実際のビジネスルールについては十分に理解していないため、デモ用のシナリオを作成します。顧客が所属できるチャネルは1つだけだとします。 Orderの1つの行から次の行に移動すると、CustomerNumberとChannelの両方の値が変化することがわかります。ただし、SalesOrderNumberが異なるためではなく、CustomerNumberが異なるため、チャネルの値が変更されます。チャネルは、CustomerNumberによって(つまり推移的に)SalesOrderNumberによって異なります。私の作成したシナリオでは、チャネルをOrderからCustomerNumberをキーとする新しいテーブル(Customer)に移動する必要があります。

BCNFに違反するには、テーブルに少なくとも1つの列を共有する複数の候補キーが必要です。どちらの設計にもこれがないため、3NFに入ると、設計はBCNFにも含まれます。

はい、テーブルを分割します。

2
Michael Green

正規化はすでに十分に説明されています。

Clustered Indexは、

  • 増え続ける
  • 狭い
  • 述語で最も頻繁に使用
  • Selectivity十分に選択的である必要があります。where句で使用する場合は、1行または2行を返す必要があります。つまり、行全体の1%または2%を返す必要があります。

    注文表

    • OrderID int identity(1,1)PK
    • SalesOrderNumber varchar(15)がnullではない

      OrderDetail TABLE

    • OrderDetailid int identity(1,1)

    • OrderID int FKクラスター化インデックスを削除する

他の表では、OrderidFKではなくSalesOrederNumberとして参照しています。 OrderIDで内部的にすべてを処理します。

SalesOrderNumberはBizにサービスを提供するためにあります。要件。

でもOrder detailテーブルほとんどの行はOrderIDを使用して取得されます

したがって、OrderidCLUSTERED INDEX。また、OrderIDは増加し続けているため、CLUSTERED INDEXは自動的にソートされます。

OrderDetailidOrderIDよりも選択的ですが、Orderidは他の利点に加えて十分に選択的です。

そのため、OrderDetailテーブルのOrderedIDをクラスター化インデックスとして持つと、各注文の順序が保持されます(OrderDetailテーブルでは、各注文が順番に並べられます)。

はい。

このようにOrderDetailテーブルを配置すると、パフォーマンスが向上しますか? OrderDetailIDとは対照的に、OrderIDを中心としたクラスタリングの利点は何ですか?

ほとんどの重要なクエリは、OrderIDのみを使用してOrderDetailテーブルからレコードを取得します。ですよね?ほとんどのクエリは述語でOrderIDを使用するため、クラスター化インデックスにはOrderidが最適です。

ただし、注文は多くのパーツで構成されるため、各OrderIDには多くの行があります。

上記のインデックスの選択性について説明しようとしました。各Orderidは最大でいくつの部分を持つことができますか?5、10、50?

最善の方法は、Real Table数百万のレコードと1つの実際のクエリでテストします。real table構造とそのdata type

1
KumarHarsh

答えは簡単です。はい!おそらくこれはアプリを変更することも意味します。

2番目のデザインははるかに優れています。 Order Date、Due Dateなどは繰り返さないでください。ただし、OrderDetailの主キーをIDに変更することを検討してください。さらに、Orderテーブルでは、IDも主キーとして配置します。もちろん、そのような列は外部キーとしてOrder Detailテーブルに存在する必要があります。注文のパーツIDが1つだけである必要があると思うのはなぜですか?あなたのビジネスがあなたを示唆しているなら、それは大丈夫です。しかし、IMO、すべてが起こる可能性があるため、これは将来的に制限になる可能性があります。

1
user179264