web-dev-qa-db-ja.com

EAV-すべてのシナリオで本当に悪いのですか?

entity-attribute-value(EAV)モデル をプロジェクトの一部のものに使用することを考えていますが、すべての Stack Overflowでの質問 end EAVをアンチパターンと呼ぶ答えまで。

しかし、すべての場合でそれが間違っているのだろうかと思います。

ショップ製品のエンティティとしましょう。名前、説明、画像、価格などの共通の機能があり、多くの場所でロジックに参加し、時計やビーチボールは完全に異なる側面で記述されるなど、(半)固有の機能を備えています。したがって、EAVはそれらの(半)固有の機能を格納するのに適していると思います。

これはすべて、製品リストを表示するために(EAVが含まれていないことを意味する)製品テーブルの十分な情報であり、1つの製品を表示する場合/最大5つの製品などを比較する場合を想定しています。 EAVを使用して保存されたデータが使用されます。

Magentoコマースでこのようなアプローチを見たことがありますが、それは非常に人気があるので、EAVが妥当な場合がありますか?

70
Giedrius

https://web.archive.org/web/20140831134758/http://www.dbforums.com/database-concepts-design/1619660-otlt-eav-design-why-do-people-hate。 html

EAVは、必要に応じてスキーマを定義する柔軟性を開発者に提供します。これは、状況によっては適切です。

一方、不適切に定義されたクエリの場合、パフォーマンスは非常に低く、他の悪い習慣をサポートする可能性があります。

言い換えれば、EAVは自分自身を吊るすのに十分なロープを提供します。この業界では、プロジェクトであなたを置き換える人は馬鹿である可能性が高いため、物事は最低レベルの複雑さで設計する必要があります。

88
maple_shaft

簡単に言えば、EAVは、属性のリストが頻繁に増加する場合や、すべての属性を列にした場合、ほとんどの行がほとんどNULLで埋められるほど大きい場合に役立ちます。そのコンテキスト外で使用すると、アンチパターンになります。

33
Karl Bielefeldt

ショップの商品エンティティを例に考えてみましょう。名前、説明、画像、価格などの共通の機能があり、多くの場所でロジックに参加し、時計やビーチボールは完全に異なる側面で記述されるなど、(半)固有の機能を持っています。 EAVはそれらの(半)固有の機能を格納するのに適していると思いますか?

のEAV構造の使用には、トレードオフであるいくつかの影響があります。

「より複雑なクエリとモデル」に対してnullである100列がないため、「行のスペースが少なくなります」とトレードオフしています。

EAVを持つことは、通常、値が文字列であり、データを入れることができます。これは有効性と制約チェックに影響を与えます。使用したバッテリーの数をEAVテーブルに何かとして入れた状況を考えてみましょう。 Cサイズのバッテリーを使用しているが、そのうちの4つ未満の懐中電灯を見つけたいとします。

select P.sku
from
  products P
  attrib Ab on (P.sku = Ab.sku and Ab.key = "batteries")
  attrib Ac on (P.sku = Ac.sku and Ac.key = "count")
where
  cast(Ac.value as int) < 4
  and Ab.value = 'C'
  ...

ここで気づくのは、値に対して適切にインデックスを使用できないことです。また、値の列がさまざまな目的で何度も使用されるため、誰かが整数ではないもの、または無効な整数(「-1」のバッテリーを使用)を入力できないようにすることもできません。

これは、製品のモデルを作成する際に影響します。ニースの型付き値が表示されますが、Map<String,String>そこに座って、あらゆる種類のstuffを入れます。これは、XMLまたはJsonにシリアル化するときにさらに影響を及ぼし、those構造に対して検証またはクエリを実行する際の複雑さを伴います。

考慮すべきパターンに対するいくつかの代替案または変更は、有効なキーを持つ別のテーブルを用意するために、自由形式のキーの代わりです。これは、データベースで文字列比較を行う代わりに、外部キーIDの同等性をチェックすることを意味します。キー自体の変更は1つの場所で行われます。あなたは既知のキーのセットを持っています。つまり、それらは列挙型として実行できます。

また、特定のクラスの製品の属性を含む関連テーブルを持つこともできます。食料品部門は、建築資材には必要のないいくつかの属性が関連付けられた別のテーブルを持つことができます(その逆も同様)。

+----------+    +--------+    +---------+
|Grocery   |    |Product |    |BuildMat |
|id (fk)   +--->|id (pk) |<---+id (fk)  |
|expiration|    |desc    |    |material |
|...       |    |img     |    |...      |
+----------+    |price   |    +---------+
                |...     |               
                +--------+               

特にEAVテーブルを呼び出すことがある。

すべての製品とすべての属性を知っている会社の在庫システムを作成しているだけではない状況を考えてみましょう。これで、他社に販売するための在庫システムを作成しています。あなたはすべての製品のすべての属性を知ることができません-彼らはそれらを定義する必要があります。

出てきたアイデアの1つは、「お客様がテーブルを変更できるようにする」というものですが、これは単に悪いことです(どこに何があるかわからなくなるため、テーブル構造のメタプログラミングに入りますroyally構造を台無しにしたり、アプリケーションを破損したりします。彼らは間違ったことを行うためのアクセス権を持ち、そのアクセス権の意味が大きくなります)。このパスについての詳細は MVC4:実行時にモデルを作成する方法?

代わりに、EAVテーブルへの管理インターフェースを作成し、それを使用できるようにします。顧客が「水玉模様」のエントリを作成したい場合、それはEAVテーブルに入力され、その処理方法をすでに知っています。

この例は Redmineのデータベースモデル で確認できます。custom_fieldsテーブルとcustom_valuesテーブルを確認できます。これらはシステムの拡張を可能にするEAVの一部です。


テーブル構造全体がリレーショナルではなくEAVのように見える場合は、 NoSQLのKVフレーバー (cassandra、redis、Mongoなど)を確認することをお勧めします。これらには、設計にotherトレードオフが伴うことがよくあり、それを使用する目的に適している場合とそうでない場合があることに注意してください。ただし、これらは具体的にはEAV構造の意図で設計されています。

あなたは読みたいかもしれません 在庫管理システムのためのSQL vs NoSQL

ドキュメント指向のNoSQLデータベース(カウチ、mongo)を使用したこのアプローチに従って、各インベントリアイテムをディスク上のドキュメントと見なすことができます...単一のドキュメント内のすべてをプルアップするのが高速です。さらに、ドキュメントは構造化されているため、1つのものをすばやく取り出すことができます。一方、特定の属性に一致するものをすべてのドキュメントで検索すると、パフォーマンスが低下する可能性があります(すべてのファイルに対して「grep」を使用した場合と比較)...すべてのトレードオフです。

別のアプローチとしては、LDAPがあり、関連するすべてのアイテムを持つベースがあり、他のタイプのアイテムに対して追加のオブジェクトクラスが適用されます。 ( LDAPを使用したシステムインベントリ を参照)

このパスをたどると、may探しているものと完全に一致するものを見つけることができます...すべてにはいくつかのトレードオフがあります。

24
user40980

6年後

JSON in Postgres がここにあるので、Postgresを使用している人のための別のオプションがあります。製品に追加のデータを添付したいだけの場合、ニーズはかなり単純です。例:

CREATE TABLE products (sku VARCHAR(30), shipping_weight REAL, detail JSON);
INSERT INTO products ('beachball', 1.0, '{"colors": ["red", "white"], "diameter": "50cm"}');

SELECT * FROM products;
    sku    | weight |               detail               
-----------+--------+------------------------------------
 beachball |      1 | {"colors": ["red", "white"], "diameter": "50cm"}

PostgresでのJSONのよりスムーズな導入は次のとおりです: https://www.compose.com/articles/is-postgresql-your-next-json-database/

Postgresは実際にはプレーンテキストのJSONではなくJSONBを保存し、そのデータに対して実際にクエリを実行したい場合に備えて、JSONBドキュメント/フィールド内のフィールドのインデックスをサポートしていることに注意してください。

また、JSONBフィールド内のフィールドは、UPDATEクエリで個別に変更できないことに注意してください。 JSONBフィールドのコンテンツ全体を置き換える必要があります。

この回答は質問に直接対処することはできませんが、EAVパターンの代替手段を提供します。これは、元の質問を熟考しているすべての人が検討する必要があります。

16
Dan Ross

通常、ルックアップテーブル、または1つまたは2つの格納された値のテーブルを作成する必要がないという利点がある他の状況で使用する場合、人々は他の方法で見ます。あなたが説明している状況、つまり基本的にアイテムのプロパティを格納している状況は、完全に正常に聞こえます(そして正規化されます)。可変数のアイテム属性を格納するためにテーブルを広げることは悪い考えです。

異種のデータを長くて薄いテーブルに格納する一般的なケースでは、必要に応じてafraidを使用して新しいテーブルを作成することはできません。 1つまたは2つの短いファットテーブルだけよりもはるかに優れています。

そうは言っても、ログにEAVテーブルを使用することで有名です。彼らはいくつかの優れたユーティリティを持っています。

7
Satanicpuppy

EAVは明示的な構造の問題を暗黙の知覚に変えます。 Xは列AとBを持つテーブルであると言うのではなく、列AとBがテーブルXを形成することを意味します。これは、ある意味では逆ですが、必ずしも1対1のマッピングはありません。 AとBは両方ともテーブル(またはタイプ)XとYにマップすると言うことができます。これは、コンテキストが関係するより複雑なドメインでは重要です。

私はこのタイプのアプローチのためにDatomicを研究してきましたが、それはあなたがそれで何をすべきかを制限する非常に便利で強力なシステムだと思います(できなかったわけではありません)。

EAVが遅い、または「自分自身を吊るすのに十分なロープを与える」ことは、私が同意する声明ではありません。むしろ、EAVの長所に重点を置き、それが問題の領域に適している場合は、検討する必要があります。

私の経験では、それは素晴らしいほぼ制約なしモデリングへのアプローチです。具体的には、Datomicの場合、それらはすべての上にセットのセマンティックを課します。関係をモデル化するモデル化の決定は、列/テーブルを再設計することなく、自由に1つから多くに決定できます。制約が不変式に違反していない限り、戻ることもできます。フードの下ですべて同じです。

EAVの問題は、Datomicのような実装の欠如にありました。これはEAVについての質問なので、Datomicに夢中になりたくはありませんが、EAVに関してすべてが正しく行われたと私が思うものの1つです。

1
John Leidegren