2 つの類似した機能のフィールドを持つデータベース設計における相反する要望
-
02-07-2019 - |
質問
さて、今「ボックスアイテム」の表を作っています。
さて、ボックス アイテムは、その使用目的やアイテムの状態に応じて、最終的に「配送」ボックスまたは「返品」ボックスに関連付けられる場合があります。
ボックス アイテムに欠陥がある可能性があります。欠陥がある場合は、ボックス アイテムの行 (IsDefective) にフラグが設定され、ボックス アイテムは (そのベンダーに返品される他のアイテムと一緒に) 「返品」ボックスに入れられます。それ以外の場合、ボックス アイテムは最終的に (発送される他のアイテムと一緒に) 「配送」ボックスに入れられます。(配送ボックスと返品ボックスにはそれぞれ独自のテーブルがあることに注意してください。すべてのボックスに共通する 1 つのテーブルはありません...ただし、可能であれば 3 番目の可能性としてそれを検討する必要があるでしょうか?)
今日は私が明確に考えていないだけかもしれませんが、この状況で何をすべきかを疑問に思い始めました。
私の直感では、たとえ一度に 1 つの関係しか発生しないとしても、考えられる関係ごとに個別のフィールドを用意する必要があると考えています。これにより、ボックス アイテムのスキーマは次のようになります。
boxItemid説明is -fefictectivetivefitive shippingboxid returnboxidなど...
これにより関係が明確になりますが、無駄に思えます (一度に使用される関係は 1 つだけであるため)。そこで、BoxID のフィールドを 1 つだけ用意し、IsDefective フィールドに基づいて、それが参照している BoxID (配送ボックス ID または返品ボックス ID) を判断できると考えました。
boxItemid説明isdefective boxidなど...
これは無駄が少ないように思えますが、私には合いません。その関係は明らかではありません。
そこで、Stackoverflow のデータベースの第一人者であるあなたに言いました。この状況であなたならどうしますか?
編集:皆さん、ご意見ありがとうございました!いろいろ考えさせられました。まず、次回このようなプロジェクトを開始するときは ORM を使用するつもりです。=) 2 つについては、今は都合が悪いので、4 バイトをバイトして 2 つのフィールドを使用します。
みなさん、またよろしくお願いします!
解決
私はPsychotic Venomとmattlantと一緒です。
ポリモーフィックなルート (別のフィールドの内容に基づいて外部キーがどのテーブルを指しているかを把握する必要がある) に進むのは面倒です。そのための制約をコーディングするのは難しいかもしれません (ほとんどのデータベースがそれをネイティブにサポートしているかどうかはわかりません。トリガーを使用する必要があると思います)。
テーブル間でアイテムが移動することはありますか?同一の定義を持つ 2 つのテーブル (1 つは返品用、もう 1 つは配送用) を使用するのが最も簡単な方法かもしれません。最初に提案した定義 (2 つの別々のフィールド) にこだわりたい場合は、まったく合理的です。
「時期尚早の最適化は諸悪の根源」などなど。無駄に思えますが、何を保存しているかを思い出してください。これらは ID であるため、おそらく単なる整数 (おそらく 4 バイト) です。レコードごとに 4 バイトを無駄にすることは基本的には何もありません。実際、アドレスなどに何かを配置するためのパディングにより、その追加のフィールドを「無料」で配置できる場合があります。それはすべて DB の設計に依存します。
ポリモーフィック ルートを選択する正当な理由がない限り (メモリが少ない組み込みシステムを使用している場合や、非常に遅い 9600bps リンクを介してレプリケーションを行う必要がある場合など)、最終的に発生する可能性のある頭痛の種にはおそらく値しません。 。これらの特殊なケースをすべてクエリに書き込む必要があるのは煩わしい場合があります。
簡単な例:isDefective フラグが設定されているかどうかに基づいて結合するかどうかを判断する 2 つのテーブル間で結合を行うのは面倒です。少なくとも私にとっては、2 つの列のうちの 1 つだけを単独で使用できるだけで、おそらく十分な手間が省けるでしょう。
他のヒント
ボックスに対して 1 つのテーブルを作成し、ボックス タイプをボックス テーブルの列にすることを検討します。これにより関係が簡素化され、ボックス タイプのクエリが容易になります。したがって、ボックス項目には boxId への外部キーが 1 つだけあります。
Hibernate で呼ばれるものを使用します サブクラスごとのテーブル, したがって、私の DB にはボックス用の 3 つのテーブルが含まれることになります。 Box
, ShippingBox
, 、 そして ReturnBox
. 。でのFK BoxItem
を指すだろう Box
.
あなたが話しているのは、ポリモーフィックな関係です。他の複数のテーブルを参照できる単一の ID。これをサポートするフレームワークはいくつかありますが、データベースの整合性にとって (潜在的に) 悪影響を及ぼします (データベースまたはアプリケーションが参照整合性を維持する必要があるかどうかは、まったく別の議論になる可能性があります)。
これはどうですか?
BoxItem:
BoxItemID, Description, IsDefective
Box:
BoxID, Description
BoxItemMap:
BoxID, BoxItemID, BoxItemType
次に、BoxItemType を列挙型、またはアプリケーションでボックスのタイプとして「返品」または「配送」として定数を定義する整数にすることができます。
上記の多態性の議論については同意します。これは不適切に使用される可能性がありますが、それでも実行可能なソリューションです。
基本的に、ボックスと呼ばれるベーステーブルがあります。次に、他に 2 つのテーブル (配送ボックスと返却ボックス) があります。これら 2 つは、それらに特別なフィールドを追加します。これらは 1:1 fk のボックスに関連付けられています。Boz ベース テーブルには、すべてのボックス タイプに共通のフィールドがあります。
BoxItem をボックス テーブルに関連付けます。適切なボックス タイプを取得する方法は、キーに基づいて子ボックスとルート ボックスを結合するクエリを実行することです。親ボックスと子ボックスの両方にあるレコードがそのタイプです。
前述したように、ボックス タイプを作成するときにそれが正しく行われるように注意する必要があります。しかし、それがテストの目的です。それらを追加するコードは 1 回記述するだけで済みます。または ORM を使用します。
ほぼすべての ORM がこの戦略をサポートしています。
IsDefective、 ShippingBoxID、配送箱関連フィールド、ReturnBoxID、および返品箱関連フィールドを含む 1 つの BoxItems テーブルだけを使用します。一部のフィールドは各レコードで常に NULL になります。
これは非常にシンプルで自明の設計なので、次の開発者が混乱する可能性は低いです。理論的には、この設計は各行に空のフィールドが保証されているため非効率的です。実際には、データベースは各行に最低限必要なストレージ サイズを設定する傾向があるため、(フィールドの数が膨大でない限り) この設計はとにかく可能な限り効率的であり、コーディングがはるかに簡単です。
私はおそらく次のようにするでしょう:
BoxTable:
box_id, box_descrip, box_status_id ...
1, Lovely Box, 1
2, Borked box, 2
3, Ugly Box, 3
4, Flammable Box, 4
BoxStatus:
box_status_id, box_status_name, box_type_id, ....
1,Shippable, 1
2,Return, 2
3,Ugly, 2
4,Dangerous,3
BoxType:
box_type_id, box_type_name, ...
1, Shipping box, ...
2, Return box, ....
3, Hazmat box, ...
このようにして、ボックス ステータスによってボックス タイプが定義され、後でさらにいくつかのステータス レベルまたはボックス タイプに拡張する必要がある場合に柔軟に対応できます。