2011-01-16 6 views
17

私は、ユーザが "オブジェクト"定義をリアルタイムで作成できるエディタを開発中です。定義には、0個以上のプロパティーを含めることができます。プロパティの名前はa型です。定義が作成されると、ユーザーはその定義のオブジェクトを作成し、そのオブジェクトのプロパティ値を設定できます。動的プロパティをサポートするスキーマ

したがって、マウスボタンをクリックすることで、ユーザーはそうする必要があります。 "Bicycle"という新しい定義を作成し、 "Numeric"型の "Size"プロパティを追加することができます。次に、 "Text"型の "Name"と呼ばれる別のプロパティーと、 "Numeric"型の "Price"という別のプロパティーがあります。それが完了すると、ユーザーは2つの「自転車」オブジェクトを作成し、各自転車の「名前」および「価格」プロパティ値を記入できるようになります。

ここでは、いくつかのソフトウェア製品でこの機能を見てきました。したがって、これはよく知られた概念でなければなりません。私の問題は、私が座ったときに始まり、このデータ構造をサポートするDBスキーマを考え出しました。なぜなら、適切な列タイプを使用してプロパティ値を格納したいからです。つまり数値プロパティ値は、例えばINTとしてデータベースに格納され、テキストプロパティ値はVARCHARとして格納されます。

まず、私はすべてのオブジェクト定義を保持するテーブルが必要になります。

Table obj_defs 

id | name  | 
---------------- 
1 | "Bicycle" | 
2 | "Book" | 

それから私は、各オブジェクト定義が持つべき性質の種類を保持するためのテーブルが必要になります。

Table prop_defs 

id | obj_def_id | name  | type | 
------------------------------------ 
1 |   1 | "Size" | ? | 
2 |   1 | "Name" | ? | 
3 |   1 | "Price" | ? | 
4 |   2 | "Title" | ? | 
5 |   2 | "Author" | ? | 
6 |   2 | "ISBN" | ? | 

私は

Table objects 

id | created | updated | 
------------------------------ 
1 | 2011-05-14 | 2011-06-15 | 
2 | 2011-05-14 | 2011-06-15 | 
3 | 2011-05-14 | 2011-06-15 | 

最後に、私はテーブルを必要とします各オブジェクトの実際のプロパティ値を保持し、一つの解決策は、このような、それぞれの可能な値のタイプごとに1つの列を有するようにこのテーブルにあるでしょう:

Table prop_vals 

id | prop_def_id | object_id | numeric | textual | boolean | 
------------------------------------------------------------ 
1 |   1 |   1 |  27 |   |   | 
2 |   2 |   1 |   | "Trek" |   | 
3 |   3 |   1 | 1249 |   |   | 
4 |   1 |   2 |  26 |   |   | 
5 |   2 |   2 |   | "GT" |   | 
6 |   3 |   2 |  159 |   |   | 
7 |   4 |   3 |   | "It" |   | 
8 |   5 |   3 |   | "King" |   | 
9 |   6 |   4 |  9 |   |   | 

私はこのスキーマを実装した場合、どのような「タイプ」希望prop_defsテーブルの列は保持されますか?各列名に対応する整数、単に列名を保持するvarchars?他の可能性は?ストアドプロシージャは何らかの形で私をここで助けますか?そして、オブジェクト2の "名前"プロパティを取得するためのSQLはどのように見えますか?

答えて

28

エンティティ属性値モデルhttp://en.wikipedia.org/wiki/Entity-attribute-value_modelと呼ばれるものを実装しています。

あなたの最後の質問に対する答えが「フェッチするSQLは何か...」というのは「太くて厄介な」傾向があるため、多くの人が悪い考え方(通常は私はそれらの1つです)と言います。ゲット悪い。

これらの批判は、ユーザーが他のオブジェクトの内側にオブジェクトを入れ子にしてしまうことを許可した後には維持される傾向があります。

最初の質問では、 "prop_defsテーブルの" type "カラムは何を保持するのですか?{"数値 "、"任意の数字 "}を保持するタイプと説明のテーブルがあれば、 {"textual"、 "String"}などです。最初の値は主キーです。次に、prop_defs列の "type"はそのテーブルの外部キーであり、 "numeric"、 "textual"などの値を保持しています。整数キーを使うのは間違っていると言われるものもあります。 「数字」、「テキスト」などあなたはに参加する必要はありません。最速のJOINはあなたがしないものです。

単一の値は、CASE文がありますつかむためにクエリ:あなたは、リレーショナルデータベースは、この種の機能を提供するのが得意ではないことを受け入れなければなりません

SELECT case when pd.type = "numeric" then pv.numeric 
      when pd.type = "textual" then pv.textual 
      when pd.type = "boolean" then pv.boolean 
    from prov_vals pv 
    JOIN prop_defs pd ON pv.prop_def_id = pv.id 
WHERE pv.object_id = 2 
    AND pd.name = "Name" 
+0

優秀な回答!ありがとうございました:) –

+2

EAVはアイテムを入れ子にする必要があるときに避けるべきことがある場合に、より良い解決策になります。 – ChrisR

+0

MongoDBのようなNoSQLソリューションでは、EAVは最終的に死ぬことができます。 –

4

を。彼らはそれを提供することはできますが、それはうまくいかないのです。 (私は間違っていると思う)。リレーショナルデータベースは、インタフェースを変更するのではなく、定義されたインタフェースに適しています。

--EAVテーブルは動的なフィールドを提供しますが、パフォーマンスは低下します。インデックス作成に疲れている。そしてそれは照会するのが複雑です。それは多くの状況で仕事を終わらせますが、大勢のユーザーがシステムに当たって大きなテーブルに崩壊する可能性があります。

- いくつかのプレースホルダー列を含む「通常の」表はパフォーマンスは問題ありませんが、わかりやすい列名があり、追加できる列数には限りがあります。また、サブタイプ分離もサポートしていません。

- 通常、開発時には実行時ではなくテーブルを作成/変更します。実行時にデータベースを変更することを本当に差別化すべきでしょうか?多分そうでないかもしれません。実行時に新しいテーブル、外部キー、およびカラムを作成することで、真の動的オブジェクトを実現し、「通常の」テーブルのパフォーマンス上の利点を得ることができます。しかし、データベースのスキーマを照会してから、すべての照会を動的に生成する必要があります。それは吸うだろう。それはインタフェースとしてのテーブルの概念を完全に破るでしょう。

関連する問題