Deal
とDealCategories
の2つのテーブルがあります。 1つの取引に多くの取引カテゴリを設定できます。
したがって、適切な方法は、次の構造を持つDealCategories
というテーブルを作成することです。
DealCategoryId (PK)
DealId (FK)
DealCategoryId (FK)
ただし、アウトソーシングチームは、次のように複数のカテゴリをDeal
テーブルに保存しました。
DealId (PK)
DealCategory -- In here they store multiple deal ids separated by commas like this: 18,25,32.
彼らのしたことは間違っているように感じますが、これが正しくない理由を明確に説明する方法がわかりません。
これが間違っていることをどのように説明すればよいですか?または多分I'm間違っている人で、これは許容できるものですか?
はい、それはひどい考えです。
行く代わりに:
SELECT Deal.Name, DealCategory.Name
FROM Deal
INNER JOIN
DealCategories ON Deal.DealID = DealCategories.DealID
INNER JOIN
DealCategory ON DealCategories.DealCategoryID = DealCategory.DealCategoryID
WHERE Deal.DealID = 1234
あなたは今行く必要があります:
SELECT Deal.ID, Deal.Name, DealCategories
FROM Deal
WHERE Deal.DealID = 1234
次に、アプリケーションコードで、コンマリストを個々の数値に分割する必要があります。次に、データベースを個別にクエリします。
SELECT DealCategory.Name
FROM DealCategory
WHERE DealCategory.DealCategoryID IN (<<that list from before>>)
このデザインアンチパターンは、リレーショナルモデリングの完全な誤解(テーブルを怖がる必要はありません。テーブルはあなたの友達です。テーブルを使用してください)、またはカンマ区切りのリストを取得してそれを分割するほうが速いという誤って誤解されているという信念が原因ですアプリケーションコードでは、リンクテーブルを追加するよりも(neverです)。 3番目のオプションは、外部キーを設定できるほどSQLに自信がない/能力がないということですが、そうであれば、リレーショナルモデルの設計とは何の関係もありません。
SQL Antipatterns (Karwin、2010)は、このアンチパターン(彼は「Jaywalking」と呼んでいます)の章全体を15〜23ページで取り上げています。また、著者は SOでの類似の質問 に投稿しています。 (この例に適用される)彼が指摘する重要な点は次のとおりです。
COUNT
、SUM
など)も、「複雑」から「ほとんど不可能」までさまざまです。開発者に、すべてのカテゴリのリストと、そのカテゴリの取引数を取得する方法を尋ねます。適切な設計では、これはSQLの4行です。VARCHAR
リストの長さの制限に遭遇します。カンマで区切られたリストが4000文字を超える場合は、とにかく、そのモンスターが地獄のように遅くなる可能性があります。TLDR:これは根本的に欠陥のある設計であり、適切にスケーリングされず、最も単純なクエリでさえも複雑さが増し、すぐに使用できるとアプリケーションの速度が低下します。
ただし、私たちのアウトソーシングチームは、次のように複数のカテゴリをDealテーブルに格納しました。
DealId(PK)DealCategory-ここでは、18,25,32のように、コンマで区切られた複数の取引IDを格納します。
onlyが特定の取引のカテゴリを照会する必要がある場合、これは実際に良い設計です。
しかし、特定のカテゴリのすべての取引を知りたい場合、それは恐ろしいことです。
また、更新、カウント、結合など、他のことを実行することは非常に困難でエラーが発生しやすくなります。
非正規化はその場所にありますが、同じデータに対して他のすべてのクエリを犠牲にして、あるタイプのクエリに対して最適化することを覚えておく必要があります。常に1つのパターンでクエリを実行することがわかっている場合は、非正規化された設計を使用すると有利な場合があります。ただし、クエリの種類にもっと柔軟性が必要になる可能性がある場合は、正規化された設計を使用してください。
他の形式の最適化と同様に、非正規化が正当化されるかどうかを決定する前に、実行するクエリを知る必要があります。
列の複数の値は、第1正規形に反しています。
また、テーブルはデータベース内でリンクされるため、速度はまったく向上しません。最初に文字列を読み取って解析し、次に「取引」のすべてのカテゴリを選択する必要があります。
正しい実装は、DealIdとDealCategoryIdを持つ「DealDealCategories」のような接合テーブルです。
悪い階層の実装?
また、DealCategoriesから別のDealCategoryへのFKは、DealCategoriesの階層/ツリーの不適切な実装のように見えます。親ID(いわゆる隣接リスト)の関係を使用してツリーを操作するのは面倒です。
階層を実装するときは、ネストされたセット(読みやすいが変更は難しい)とクロージャテーブル(全体的なパフォーマンスは最高ですが、メモリ使用量が多すぎる可能性があります-DealCategoriesには多すぎません)を確認してください!