web-dev-qa-db-fra.com

EAV - est-ce vraiment mauvais dans tous les scénarios?

Je pense utiliser un modèle entity-attribute-value (EAV) pour certaines des choses dans l'un des projets, mais tous questions à ce sujet dans Stack Overflow end jusqu'aux réponses appelant EAV un anti-modèle.

Mais je me demande si c'est mal dans tous les cas.

Disons que l'entité de produit de magasin, elle a des caractéristiques communes, telles que le nom, la description, l'image et le prix, qui participent à la logique de nombreux endroits et a des caractéristiques (semi) uniques, comme la montre et le ballon de plage qui seraient décrites par des aspects complètement différents. Je pense donc que l'EAV conviendrait pour stocker ces caractéristiques (semi) uniques.

Tout cela suppose que pour afficher la liste des produits, il y a suffisamment d'informations dans le tableau des produits (cela signifie qu'aucun EAV n'est impliqué) et juste lorsque vous affichez un produit/comparez jusqu'à 5 produits/etc. les données enregistrées avec EAV sont utilisées.

J'ai vu une telle approche dans le commerce Magento et elle est assez populaire, alors y a-t-il des cas où l'EAV est raisonnable?

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 donne une flexibilité au développeur pour définir le schéma selon les besoins et cela est bon dans certaines circonstances.

En revanche, il fonctionne très mal dans le cas d'une requête mal définie et peut prendre en charge d'autres mauvaises pratiques.

En d'autres termes, l'EAV vous donne suffisamment de corde pour vous accrocher et dans cette industrie, les choses devraient être conçues au plus bas niveau de complexité car le gars qui vous remplacera sur le projet sera probablement un idiot.

88
maple_shaft

En un mot, EAV est utile lorsque votre liste d'attributs augmente fréquemment, ou lorsqu'elle est si grande que la plupart des lignes seront remplies principalement de NULL si vous faites de chaque attribut une colonne. Il devient un anti-modèle lorsqu'il est utilisé en dehors de ce contexte.

33
Karl Bielefeldt

Disons que l'entité de produit de magasin, elle a des caractéristiques communes, comme le nom, la description, l'image, le prix, etc., qui participent à la logique de nombreux endroits et a des caractéristiques (semi) uniques, comme la montre et le ballon de plage qui seraient décrites par des aspects complètement différents . Je pense donc que l'EAV conviendrait pour stocker ces caractéristiques (semi) uniques?

L'utilisation d'une structure EAV pour a plusieurs implications qui sont des compromis.

Vous échangez un "moins d'espace pour la ligne car vous n'avez pas 100 colonnes qui sont null" contre "des requêtes et un modèle plus complexes".

Avoir un EAV signifie généralement que la valeur est une chaîne dans laquelle on peut bourrer n'importe quelles données. Ceci a alors des implications sur la validité et la vérification des contraintes. Considérez la situation où vous avez mis le nombre de piles utilisées comme quelque chose dans le tableau EAV. Vous voulez trouver une lampe de poche qui utilise des piles de taille C, mais moins de 4 d'entre elles.

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'
  ...

La chose à réaliser ici est que vous ne pouvez pas utiliser raisonnablement un index sur la valeur. Vous ne pouvez pas non plus empêcher quelqu'un d'y insérer quelque chose qui n'est pas un entier ou un entier non valide (utilise des piles '-1') car la colonne de valeur est utilisée à plusieurs reprises à des fins différentes.

Cela a alors des implications pour essayer d'écrire un modèle pour le produit. Vous aurez les valeurs typées Nice ... mais vous allez aussi avoir un Map<String,String> simplement assis là avec toutes sortes de trucs dedans. Cela a ensuite d'autres implications lors de sa sérialisation en XML ou Json et la complexité d'essayer de faire de la validation ou des requêtes sur ces structures .

Certaines alternatives ou modifications au modèle à considérer consistent, au lieu d'une clé de forme libre, à avoir une autre table avec des clés valides. Cela signifie qu'au lieu de faire des comparaisons de chaînes dans la base de données, vous comparez l'égalité des identifiants de clés étrangères. La modification de la clé elle-même se fait en un seul endroit. Vous disposez d'un ensemble de clés connu, ce qui signifie qu'elles peuvent être effectuées en tant qu'énumération.

Vous pouvez également avoir des tables associées qui contiennent des attributs d'une classe spécifique de produit. Un service d'épicerie pourrait avoir une autre table qui a plusieurs attributs qui lui sont associés dont les matériaux de construction n'ont pas besoin (et vice versa).

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

Il y a des moments où en particulier appelle une table EAV.

Considérez la situation où vous n'écrivez pas seulement un système d'inventaire pour votre entreprise où vous connaissez chaque produit et chaque attribut. Vous écrivez maintenant un système d'inventaire à vendre à d'autres sociétés. Vous ne pouvez pas connaître chaque attribut de chaque produit - ils devront les définir.

Une idée qui en ressort est "nous allons laisser le client modifier la table" et c'est tout simplement mauvais (vous entrez dans la méta-programmation pour les structures de table parce que vous ne savez plus où se trouve, ils peuvent royalement gâcher la structure ou corrompre l'application, ils ont le droit de faire de mauvaises choses et les implications de cet accès deviennent importantes). Il y a plus sur ce chemin à MVC4: Comment créer un modèle au moment de l'exécution?

Au lieu de cela, vous créez l'interface d'administration d'une table EAV et autorisez son utilisation. Si le client veut créer une entrée pour "polkadots", il va dans la table EAV et vous savez déjà comment y faire face.

Un exemple de cela peut être vu dans le modèle de base de données pour Redmine vous pouvez voir la table custom_fields et la table custom_values ​​- ce sont des parties de l'EAV qui permettent au système d'être étendu.


Notez que si vous trouvez que votre structure de table entière ressemble à EAV plutôt qu'à relationnelle, vous voudrez peut-être regarder version KV de NoSQL (cassandra, redis, Mongo ,. ...). Sachez que ceux-ci sont souvent accompagnés d'autres compromis dans leur conception qui peuvent ou non être adaptés à l'utilisation que vous en faites. Cependant, ils sont spécifiquement conçus avec l'intention d'une structure EAV.

Vous voudrez peut-être lire SQL vs NoSQL pour un système de gestion des stocks

En suivant cette approche avec une base de données NoSQL orientée document (canapé, mongo), vous pouvez considérer chaque élément d'inventaire comme un document sur un disque ... tout tirer dans un seul document est rapide. En outre, le document est structuré de sorte que vous puissiez retirer rapidement une seule chose. D'un autre côté, rechercher dans tous les documents des choses qui correspondent à un attribut particulier peut avoir moins de performances (comparer en utilisant 'grep' par rapport à tous les fichiers) ... c'est tout un compromis.

Une autre approche serait LDAP où l'on aurait une base avec tous ses éléments associés, mais qui aurait alors également des classes d'objets supplémentaires qui lui seraient appliquées pour les autres types d'éléments. (voir Inventaire système utilisant LDAP )

Une fois que vous suivez ce chemin, vous pouvez trouver quelque chose qui correspond exactement à ce que vous recherchez ... bien que tout soit assorti de compromis.

24
user40980

6 ans plus tard

Maintenant que JSON dans Postgres est là, nous avons une autre option, pour ceux qui utilisent Postgres. Si vous souhaitez uniquement associer des données supplémentaires à un produit, vos besoins sont assez simples. Exemple:

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"}

Voici une introduction plus fluide à JSON dans Postgres: https://www.compose.com/articles/is-postgresql-your-next-json-database/ .

Notez que Postgres stocke en fait JSONB, pas du texte brut JSON, et qu'il prend en charge les index sur les champs à l'intérieur d'un document/champ JSONB, au cas où vous découvririez que vous souhaitez réellement interroger ces données.

Notez également que les champs d'un champ JSONB ne peuvent pas être modifiés individuellement avec une requête UPDATE; vous devrez remplacer tout le contenu du champ JSONB.

Cette réponse ne répond peut-être pas directement à la question, mais elle offre une alternative à un modèle d'EAV, qui devrait être envisagée par quiconque réfléchit à la question d'origine.

16
Dan Ross

Généralement, les gens regardent dans l'autre sens si vous l'utilisez pour des tables de recherche ou dans d'autres situations où l'avantage est de ne pas avoir à créer de tables pour une ou deux valeurs stockées. La situation que vous décrivez, où vous stockez essentiellement les propriétés d'un élément, semble parfaitement normale (et normalisée). Élargir une table pour stocker un nombre variable d'attributs d'élément est une mauvaise idée.

Pour le cas général de stockage de données disparates dans une longue table mince ... Vous ne devriez pas être peur pour créer de nouvelles tables si vous en avez besoin, et avoir seulement une ou deux longues tables maigres n'est pas beaucoup mieux que d'avoir seulement une ou deux tables courtes de matières grasses.

Cela étant dit, je suis connu pour utiliser des tables EAV pour la journalisation. Ils ont une bonne utilité.

7
Satanicpuppy

EAV transforme le problème de la structure explicite en perception implicite. Plutôt que de dire que X est un tableau avec les colonnes A et B. Vous impliquez que les colonnes A et B forment le tableau X. C'est l'inverse dans un sens mais il n'y a pas nécessairement de mappage un à un. Vous pourriez dire que A et B mappent tous deux sur la table (ou tapez) X et Y. Cela pourrait être important dans le domaine le plus impliqué où le contexte compte.

J'ai étudié Datomic, pour ce type d'approche et je pense que c'est un système très utile et puissant avec des limites sur ce que vous devriez faire avec (pas que vous ne pouviez pas).

Que l'EAV serait lent, ou "vous donne assez de corde pour vous accrocher" n'est pas une déclaration avec laquelle je serais d'accord. Au contraire, je mettrais davantage l'accent sur les forces de l'EAV et si cela convient à votre espace problématique, vous devriez le considérer.

D'après mon expérience, c'est une merveilleuse presque sans contrainte approche de la modélisation. Plus précisément, dans le cas de Datomic, ils imposent un ensemble sémantique par dessus tout. Toute décision de modélisation qui modélise une relation peut librement passer de une à plusieurs sans avoir à repenser les colonnes/tables. Vous pouvez également revenir en arrière tant que la contrainte ne viole pas l'invariant. C'est pareil sous le capot.

Le problème avec EAV a été dans mon esprit avec le manque d'une implémentation comme Datomic. Puisqu'il s'agit d'une question sur l'EAV, je ne veux pas m'extasier sur Datomic, mais c'est l'une de ces choses où je pense qu'ils ont tout bien réglé en ce qui concerne l'EAV.

1
John Leidegren