7

私は、製品ごとに異なる可能な属性の束を持つ製品の束を持っています。たとえば、製品Aには名前、サイズ、色、形があります。製品Bには、名前、カロリー、砂糖などがあります。これを解決する1つの方法は、次のとおりです。

1)テーブルを作成する

Products (id, name)
Attributes (id, name)
Product_Attributes (product_id, attribute_id, value as string)

これにより最大限の柔軟性が得られますが、理由はわかりませんが、多くの人がこれに反対することを勧めていると聞いています。つまり、これらのテーブルがTeams、Players、Team_Playersと呼ばれる場合、これが適切なリレーショナル設計であることに同意します。

これがなぜ悪いのかを私に説明する人は誰でも、基本的ないくつかの基本的な初期テーブル(object、attribute、object_attributeなど)を超えて実際のテーブルを作成することがない、完全に柔軟なリレーショナル設計のコンテキストでそうします。すべてが同意できるのは悪いことです。ただし、これははるかに限定されたバージョンであり(システム内のすべてのオブジェクトではなく、製品のみ)、これら2つのアーキテクチャをグループ化することは公平ではないと思います。

この設計を非常に悪くする原因となる問題(経験または理論)は何ですか?

2)これを解決する別の方法は、サイズ、色、形状、重量、砂糖などの列の束を含むProductテーブルを作成し、柔軟性を持たせるために最後にいくつかの追加の列を含めることです。これにより、ほとんどがNULLで満たされた一般的にまばらな行が作成されます。人々はこのアプローチを好む傾向がありますが、私の質問は、このアプローチがパフォーマンス上の利点を失う前に、いくつの列を持つことができるかということです。200の列がある場合、これはもはや賢明な動きではないと思いますが、100の列はどうでしょうか。50列?25列?

3)私が知っている最後のアプローチは、すべての属性をblob(おそらくJSON)としてProductsテーブルの単一の列に格納することです。私はこのアプローチが好きですが、それは正しく感じられません。クエリは難しいです。また、後で属性の名前を簡単に変更できるようにする場合は、すべてのレコードを個別に解析するか、IDを使用してBLOBにキーを設定する必要があります。idパスに移動すると、別のテーブル属性が必要になります。属性を上からアプローチ#1のように見せ始めますが、attribute_idをblobに結合できないため、何もクエリしたくないと思います。属性名で。

このアプローチで私が気に入っているのは、1つの製品にクエリを実行でき、コード内でその製品が持つすべてのプロパティに簡単にアクセスできることです。また、製品を削除しても、他のテーブルをクリーンアップする必要はありません。一貫性を保つのは簡単です。

4)いくつかのRDBMSで強く型付けされたxml形式にインデックスを付けることができることについていくつか読んだことがありますが、正直なところ、このアプローチについてはよくわかりません。

ハマった。アプローチ#1が最善の策だと思いますが、私が読んだすべてのことは、そのように悪臭を放っています。与えられた状況に最適な方法を決定できるように、この問題について考える正しい方法は何ですか?私がリストしたものよりも多くのアイデアが明らかに歓迎されています!

4

4 に答える 4

10

「エンティティ属性値のアンチパターン」でGoogle検索を実行すると、このトピックについて多くのことを見つけることができます。

このアプローチの問題の1つは、メタデータと実際のデータが混在してしまうことです。「属性」は、「値」列に正確に何が保持されているかをデータベースに通知する必要があります。これにより、フロントエンドやレポートソフトウェアなどでこのデータを処理することが非常に困難になる可能性があります。

次に、データベース内のデータの整合性を実際に適用するのに非常に苦労することになります。あなたの製品が「重量」の属性を持っているとき、誰かが値に「22インチ」を入れないようにするにはどうすればよいですか?または完全に非数値。「まあ、私のアプリケーションはそれを処理します」と言うかもしれません。次に、アプリケーションはその処理方法を知っている必要があるため、新しい属性を追加するたびにアプリケーションを変更する必要があります。そのすべての作業を実行する場合は、新しい列を追加するだけです。

第三に、特定の製品が必要なすべての属性を備えていることをどのように強制しますか?行では、列をNOT NULLにすることができ、その行をデータベースに取り込むために必要になります。EAVモデルではそれを強制することはできません。

第4に、この種のモデルは通常、多くの混乱を招きます。人々は、どの「属性」がサポートされているかわからないか、属性を複製するか、レポートを作成するときに属性を処理するのを忘れます。たとえば、「Weight(kg)」の属性と「Weight(lbs)」の別の属性があり、誰かが「データベースで最も重い製品は何ですか?」と尋ねたとします。両方の属性をチェックする必要があることを覚えておいてください。

第五に、このモデルは通常、怠惰にもつながります。ねえ、私たちのシステムが処理できる製品の分析を実際に行う理由はありません。何が起こっても、いくつかの属性を追加するだけだからです。私の経験では、企業は、このようなアンチパターンに頼るよりも、優れたデータベース設計を作成するために必要な分析を行う方がはるかに優れています。データベース、アプリケーション、そしておそらくビジネスについても学びます。

第6に、特定の製品の1行のデータを取得するには、多くの結合が必要になる場合があります。属性を個別の行として返すこともできますが、これらの製品などを一覧表示するためにカスタマイズされたリストボックスを作成する必要があります。同様に、このモデルに対して検索クエリを作成することは非常に困難であり、これらの状況の両方でパフォーマンスの問題があります。

これらは、私が何年にもわたって遭遇した問題のほんの一部です。他にもあると思います。

システムの正しいソリューションは、ビジネスとアプリケーションの詳細に大きく依存します。製品が共通の属性を共有するいくつかのカテゴリに分類される場合は、まばらな行ではなく、サブタイプテーブルの使用を検討することをお勧めします。

于 2011-06-24T20:22:51.387 に答える
2

このアプローチが非常に悪い理由は、すべての属性を取得するためにテーブルに結合する必要がある回数がわからないためです。さらに、同じテーブルに20回参加すると、大規模なパフォーマンスブロックが作成される傾向があります。製品はシステムの中心であり、パフォーマンスにとって重要な場所になると思います。

ここで、製品の属性が大幅に異なると言います。同意しません。価格、単位、サイズ、色、寸法、重量など、多数の製品に共通する多くの属性があります。これらは、共通のプロパティとして製品テーブルに含まれている必要があります。これらは、ユーザーが商品を選ぶときに検索する可能性が最も高いものでもあります。

他のプロパティは説明として役立ちますが、他のほとんどの場合には役立ちません(検索されたり、注文の詳細に入れられたりすることはありません)。それらを説明またはメモフィールドに入力します。

最後に、異なる可能性のあるいくつかの属性が残ります。しかし、それらはどのように異なりますか?それらは特定のタイプの製品に共通ですか(本にはこれらの属性があり、カメラにはこれらの属性があります)、そのタイプの製品に関連する表がうまく機能する可能性があります。

仕事を終えてこれをすべて理解したら、EAVテーブルの柔軟性を追加します(まだ必要な場合)。上記の手順は、実際の要件の98%以上をカバーする必要があります。

(また、注文に記録する必要のある属性フィールドがわからない場合は、注文詳細テーブルを設計するのは難しいです。そのために製品テーブルに依存することはできません)

(ああ、私は@Tom Hが言っていることに心から同意します。)

于 2011-06-24T20:30:33.693 に答える
2

つまり、これらのテーブルがTeams、Players、Team_Playersと呼ばれる場合、これが適切なリレーショナル設計であることに同意します。

いいえ、しません。これが理由です。

あなたはこれから始めました。

Products (id, name)
Attributes (id, name)
Product_Attributes (product_id, attribute_id, value as string)

ID番号を削除して、実際に何が起こっているかを確認しましょう。(わかりやすくするために列名を長くします。)

Products (product_name)
Attributes (attribute_name)
Product_Attributes (product_name, attribute_name, value as string)

そしてそれをチームやプレーヤーに翻訳します。。。

Teams (team_name)
Players (player_name)
Team_Players (team_name, player_name, value as string)

したがって、サンプルデータの場合は

Team                   Player             Value
--
St. Louis Cardinals    Boggs, Mitchell    ?
St. Louis Cardinals    Carpenter, Chris   ?
St. Louis Cardinals    Franklin, Ryan     ?
St. Louis Cardinals    Garcia, Jaime      ?

疑問符の代わりに一体何が属しますか?プレイしたゲームの数を記録したいとします。これで、サンプルデータは次のようになります。

Team                   Player             Value
--
St. Louis Cardinals    Boggs, Mitchell    23
St. Louis Cardinals    Carpenter, Chris   15
St. Louis Cardinals    Franklin, Ryan     19
St. Louis Cardinals    Garcia, Jaime      14

打率も保存したいですか?できません。ミッチ・ボッグズが23試合でプレーしたか、23ヒットを記録したか、23ランを記録したか、23打席を記録したか、23打席を記録したかをデータベースで確認できないため、打率を保存できないだけでなく、または23回打った。

于 2011-06-24T20:31:53.177 に答える
2

柔軟なデータモデルには多くの問題がありますが、最初に問題になる可能性があるのは、クエリがすぐに扱いにくくなるという事実です。たとえば、すべての商品のサイズ属性を取得する場合、クエリは比較的簡単です。

SELECT p.name product_name, 
       pa.value product_size
  FROM product p    
         left outer join product_attribute pa on (p.product_id = pa.product_id)
         left outer join attribute a on (pa.attribute_id = a.attribute_id and 
                                         a.name          = 'size')

サイズや色などの他の属性を取得したい場合は、物事が難しくなります

SELECT p.name product_name, 
       pa_size.value product_size
       pa_color.value product_color
  FROM product p    
         left outer join product_attribute pa_size on (p.product_id = pa_size.product_id)
         left outer join product_attribute pa_color on (p.product_id = pa_size.product_id)
         left outer join attribute a_size on (pa_size.attribute_id = a.attribute_id and 
                                              a_size.name          = 'size')
         left outer join attribute a_color on (pa_color.attribute_id = a.attribute_id and
                                              a_color.name         = 'color')

非常に迅速に、10個の属性を取得したり、複雑な検索を記述したりする場合(色が青でサイズが中程度の製品を表示)、開発者が記述および保守する場合とデータベースオプティマイザーの場合の両方でクエリが非常に複雑になり始めます。のクエリプランを生成します。30個のテーブルを結合する場合、オプティマイザーは、妥当な時間枠でクエリプランを生成できるように、非常に迅速に検討するプランのツリーを整理する必要があります。そのため、オプティマイザーは有望なパスを早期に破棄し、多くのクエリに対して最適ではないパスを生成する傾向があります。

これは、開発者がクエリを正しく取得できないか、開発者がクエリを十分に迅速に返すことができないため、新しい開発がボトルネックになるポイントに非常に迅速に到達することを意味します。有効な属性が何であるかを判断するための要件を収集しないことで事前に節約したときはいつでも、「この腐敗したデータモデルから必要なデータを取得できないのはなぜですか?」の47回目の反復ですぐに使い果たされます。

開発者にとってのこのコストを超えて、組織全体に多くのコストを生み出すことになります。

  • この種のデータモデルをうまく処理するクエリツールはありません。そのため、現在お気に入りのクエリツールを起動してデータベースからいくつかのレポートを実行できるすべてのユーザーは、開発者がレポートを作成して抽出を行うのを待って立ち往生しています。
  • データ品質の実施は非常に困難になります。複数の属性を含む条件を確認するのは非常に困難になります(つまり、商品のサイズが中程度の場合、重量は1〜10ポンドである必要があり、商品の高さが指定されている場合は幅も必要です)。チェックします。彼らは、これらの種類の規則が違反されている場所を特定するためのレポートを作成しません。したがって、データは最終的にデータのビットバケットになり、ダウンストリームプロセスは、十分に完了していないために使用できないと判断します。
  • コアエンティティを理解することが全体としてはるかに優れた設計につながる可能性がある場合、初期要件の議論の多くを将来に移しすぎています。製品の最初のバージョンがサポートする必要のある一連の属性に同意できない場合は、そのバージョンが何をするのかを本当に理解していません。非常に一般的なアプリケーションのコーディングに成功したとしても、それを構築すると、構成に多くの時間がかかることを意味します(その時点で、誰かがサポートする属性を把握する必要があるため)。そして、アプリケーションが構成されているときに、属性が定義されたときにのみ明らかになった大量の要件を見逃していることに気付くでしょう。高さが指定されている場合、幅が必要かどうかわからない場合は、幅が必要かどうかはわかりません。彼ら'
    最悪の場合、構成中のこの問題への対応は、ビジネスルールを指定し、ワークフローを指定する柔軟な方法を提供する必要があることを即座に判断して、アプリケーションを構成するユーザーが新しい属性を追加するときにビジネスルールをすばやくコーディングできるようにすることです。また、属性をグループ化するか、特定のページをスキップすることで、アプリケーションのフローを制御できるようにします(つまり、製品タイプが自動車の場合はメーカーとモデルが必要なページがあり、今はそのページをスキップします)。しかし、それを行うには、開発環境全体を構築することになります。そして、製品を構成している人々に実際にアプリケーションをコーディングする仕事をプッシュするつもりです。開発環境の構築が本当に得意でない限り、
于 2011-06-24T20:45:52.480 に答える