データベースを計画するとき、次のような設定になりました。
Company
、Product
、Person
があります。
ジャンクションテーブルCompany_Product
を介して、Company
とProduct
の間には多対多の関係があります。これは、特定の会社が複数の製品(「車」など)を生産する場合があるためですと「自転車」)だけでなく、「自動車」などの特定の製品も複数の会社で製造できます。ジャンクションテーブルCompany_Product
には、特定の会社が特定の製品を販売する価格である追加のフィールド「price」があります。
ジャンクションテーブルCompany_Product
を介して、Company_Product_Person
とPerson
の間には別の多対多の関係があります。はい。これは、すでにジャンクションテーブルになっている1つのエンティティを含む多対多の関係です。これは、Personがcompany1の車やcompany2の自転車などの複数の製品を所有でき、同じperson_productを複数の人が所有できるためです。たとえば、person1とperson2の両方が車を購入した可能性があるためです。会社1。ジャンクションテーブルCompany_Product_Person
には、company_productを購入したときの人の考えが含まれる追加のフィールド「thoughts」があります。
これは一般的に受け入れられるものですか、それとも何か問題があるという兆候ですか?奇妙な場合、より良い解決策は何ですか?
私はこれでいくつかの問題に遭遇してきました( これなど )ので、データベースのセットアップが最初から間違っているのではないかと思っていました。
データベースの論理設計を作成する際には、「ジャンクションテーブル」の観点から考えるのではなく、関係の観点から考える必要があります。
最初の「ジャンクションテーブル」は、「Company販売Product for Price "」という関係に対応しているようです。 2番目の「ジャンクションテーブル」は、「Personが所有Product -Companyによって製造された)」という関係に対応しているようです。
完全なコンテキストに依存しますが、2番目のリレーションは、Company
、Product
、およびPerson
テーブルへの外部キーを持ち、他の「ジャンクションテーブル」への接続。これにより、会社が製造したことのない製品を個人が所有していると主張するリスクが高まりますが、その製品を偶然所有した人の所有権情報をすべて失うことなく、「販売製品」テーブルから行を削除することもできます。その会社から。多分これはあなたにとって問題ではありません、その場合これはあなたが提案する方法でテーブルを構造化しない理由ではありません、そして私が前に述べたリスクisテーブルを構造化する理由ですあなたが提案する方法で。
より一般的に、私がお勧めするのは(「テーブル」や「ジャンクションテーブル」の観点からではなく、関係を考えること以外に)物事が変化したときに何が起こるかを考えることです。たとえば、人がさまざまな製品に費やした金額を計算するとします。価格が変更される可能性がある場合、提案された表現(および追加情報なしの私の提案)ではこれを行うことはできません。その人は価格が異なるときに製品を購入した可能性があるためです。テンポラルデータベーステクニックはこれらの状況を一般的に処理できますが、これを完全に行うことはしばしばやり過ぎです。それでも、状況をより正確にモデル化する傾向があるため、一時データベースを確認することをお勧めします。そこから、どのデータ(もしあれば)が重要ではないかを検討することができるため、失う可能性があります。 (時間データベースは通常「挿入専用」です。)データが時間の経過とともにどのように変化するかを考慮に入れると、元の提案や私の提案とは異なるスキーマが必要になると思います。
2つのテーブル(AB
)の間にジャンクションがあり、さらにそれらと別のテーブル(ABC
)の間にジャンクションがあるとします。
AB
は非常に小さいリレーションである可能性があるため、RAMに保持できますが、ABC
は巨大で適合しません。したがって、AB
に触れるクエリは、ABC
へのクエリよりも高速になります。 A
のB
およびABC
フィールドのみの個別のインデックスは、一意のAB
ペアのインデックスよりもはるかに大きくなります。
OTOH FKでABC
をAB
に依存させません。代わりに、A
、B
、およびC
に直接依存するようにします。
OPはこちら。
提供された回答を読み、主題についてさらに調査して考えた後、私のセットアップ自体には技術的に問題はないと結論付けました。しかし、実際的な問題に直面していたため、スキームの関係を少し修正することで解決策を見つけました。私の問題が私が使用していたJavaScript ORMに固有であるかどうか(つまり sequelize )か、他のORMにも存在するかどうかはわかりませんが、それにも関わらず、意味のある別の設定が見つかり、この問題を回避します。
したがって、私もここに自分の答えを投稿することにしました。同じような状況で誰かがつまずいた場合、おそらく私が行ったようにスキームを変更すると役立つでしょう(ただし、元のスキームは技術的に間違っていません)。
古いアプローチの分析
まず第一に、私の質問で与えられた両方のジャンクションテーブルは、「単なる」ジャンクションテーブル以上のものでした。それらは単に、どの要素がどの要素に関連付けられているかを定義するためのツールではなく、より多くのものでした。
彼らはまた、追加情報も持っていました(それぞれ「価格」と「思考」のフィールド)。
最初の1つ、
Company_Product
、他のテーブル自体との関係もありました。厳密に言えば、これは技術的に間違っているわけではありませんが、同じものを表すようにデータベースを構造化するより自然な方法があります。さらに、この新しいアプローチにより、必要なクエリを作成することが非常に簡単になります。
解決策:新しいアプローチ
購入可能なアイテムと購入自体をモデル化していることがわかると、解決策は高くなります。この情報を多対多の関係のジャンクションテーブル内に "偽装"するのではなく、独自のテーブルを使用して、これらの情報をスキーマ内の明示的なエンティティとして保持します。
だから、最初に、明確にするために、モデルの名前を変更しましょう:
Company
は残りますCompany
Product
はProductType
になりますCompany_Product
はProduct
になりますPerson
は残りますPerson
Company_Product_Person
はPurchase
になりますそして、それがわかります:
Product
には、1つのCompany
と1つのProductType
があります。逆に、同じCompany
は複数のProduct
に関連付けることができ、同じProductType
は複数のProduct
に関連付けることができます。Purchase
には、1つのProduct
と1つのPerson
があります。逆に、同じProduct
は複数のPurchase
に関連付けることができ、同じProduct
は複数のPerson
に関連付けることができます。多対多の関係はもう存在しないことに注意してください。
[...]
単純なジャンクションテーブル以上のジャンクションテーブルを使用する代わりに、多対多の関係を取り除き、ジャンクションテーブルをスキームの本格的なエンティティに「昇格」させました。実際、テーブルは同じです。変化は関係とそれらを見る方法だけにありました。