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


65

Je pense utiliser un modèle EAV (entité-attribut-valeur) pour certains éléments de l'un des projets, mais toutes les questions à ce sujet dans Stack Overflow aboutissent à des réponses appelant EAV un anti-modèle.

Mais je me demande si c'est ce qui ne va pas dans tous les cas.

Supposons qu'une entité de produit de magasin ait des caractéristiques communes, telles que nom, description, image et prix, qui participent à la logique de nombreux lieux et présente des caractéristiques (semi) uniques, telles que la montre et le ballon de plage, qui seraient décrites sous des aspects complètement différents. Je pense donc que EAV conviendrait pour stocker ces caractéristiques (semi) uniques.

Tout cela suppose que, pour afficher la liste des produits, il suffit d’informations dans le tableau des produits (c’est-à-dire qu’il n’ya pas de fichier EAV) et juste lorsqu’un produit est présenté / comparé à 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 très populaire, y a-t-il des cas où EAV est raisonnable?


2
@busy_wait Tables "Entity-Attibute-Value" - voir Modèle d'entité-attribut-valeur sur Wikipedia .
Ross Patterson

Pour un exemple de modèle EAV fonctionnant très bien, jetez un œil à la base de données Datomic. Il stocke tout dans le modèle EAVT (T est un "horodatage", plutôt un identifiant de transaction). Leur [documentation d'indexation] (docs.datomic.com/indexes.html) semble le mieux montrer. Pour un exemple de fonctionnement terrible de EAV, voir Wordpress .
Dan Ross

Réponses:


81

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

EAV permet au développeur de définir le schéma selon ses besoins, ce qui est utile dans certaines circonstances.

D'autre part, il fonctionne très mal dans le cas d'une requête mal définie et peut supporter d'autres mauvaises pratiques.

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


32
Aimez la dernière phrase.
Zohar Peled

2
Lien pourri. Existe-t-il une version en cache quelque part?
Wildcard

1
Ne suivez pas le lien. La page se charge lentement et n'est pas utile. En outre, les forums de style ancien comme ça pue. Utilisez plutôt un débordement de pile! Upvote bonnes / utiles réponses et poussez la corbeille.
Jess

29

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


16
Je remplacerais "fréquemment" par "a besoin de pouvoir changer d'opération au moment de l'exécution".
Doc Brown

3
Nous pouvons raccourcir encore plus Doc Brown en utilisant le mot assez bien compris "dynamique" - EAV est utile lorsque votre liste d'attributs peut changer de manière dynamique.
Alexander Mills

Encore plus loin dans "quand vos attributs peuvent changer" - "dynamiquement" est un peu redondant dans ce contexte :)
Wranorn

1
Est-il nécessairement plus utile que, par exemple, que le formulaire permettant de modifier un attribut effectue une opération CREATE TABLEpour le nouvel attribut?
Damian Yerrick

@DamianYerrick approche intéressante. Avez-vous utilisé cela en production?
digout le

21

Supposons qu'une entité de produit de magasin ait des caractéristiques communes, telles que le nom, la description, l'image, le prix, etc., qui participent à la logique de nombreux lieux et présente des caractéristiques (semi) uniques, telles que la montre et le ballon de plage. . Donc, je pense qu'EAV conviendrait pour stocker ces caractéristiques (semi) uniques?

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

Vous négociez "moins d'espace pour la ligne, car vous ne disposez pas de 100 colonnes 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 rentrer toutes les données. Ceci a alors des implications sur la vérification de la validité et des contraintes. Considérez le cas où vous avez mis le nombre de piles utilisées dans le tableau EAV. Vous voulez trouver une lampe de poche utilisant 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 un index de manière raisonnable sur la valeur. Vous ne pouvez pas non plus empêcher quelqu'un d'introduire quelque chose qui n'est pas un entier ou un entier non valide (utilise des piles '-1') car la colonne de valeurs est utilisée encore et encore à des fins différentes.

Cela a alors des implications pour essayer d’écrire un modèle pour le produit. Vous aurez les bonnes valeurs dactylographiées ... mais vous allez également avoir une Map<String,String>assise juste avec toutes sortes de choses dedans. Cela a alors des implications supplémentaires lors de la sérialisation en XML ou Json et de la complexité d'essayer de valider ou d'interroger ces structures.

Certaines alternatives ou modifications du modèle à prendre en compte 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 vérifiez par rapport à l'égalité des identifiants de clé étrangère. Changer la clé elle-même se fait en un seul endroit. Vous avez un jeu de clés connu, ce qui signifie qu'elles peuvent être effectuées en tant qu'énum.

Vous pouvez également disposer de tables associées contenant les attributs d'une classe de produit spécifique. Un département d'épicerie peut avoir une autre table qui a plusieurs attributs 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 qui appellent particulièrement une table EAV.

Pensez à la situation dans laquelle vous n'êtes pas simplement en train d'écrire un système d'inventaire pour votre entreprise dans lequel vous connaissez chaque produit et chaque attribut. Vous écrivez maintenant un système d'inventaire à vendre à d'autres entreprises. Vous ne pouvez pas connaître tous les attributs de chaque produit - ils devront les définir.

Une idée qui en ressort est "nous laisserons 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, elles peuvent corrompre royalement ou corrompre l'application, ils ont le droit de faire de mauvaises choses et les implications de cet accès deviennent importantes). Il existe plus d'informations sur ce chemin sur MVC4: Comment créer un modèle au moment de l'exécution?

Au lieu de cela, vous créez l'interface administrative dans 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 gérer cela.

Un exemple de ceci 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 permet d'étendre le système.


Notez que si vous trouvez que votre structure de table entière ressemble à EAV plutôt que relationnelle, vous voudrez peut-être examiner la version KV de NoSQL (cassandra, redis, mongo, ...). Sachez que ceux-ci viennent souvent avec d’ autres compromis dans leur conception qui peuvent ou non être approprié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 d'inventaire

En suivant cette approche avec une base de données NoSQL orientée document (divan, mongo), vous pouvez considérer chaque article d'inventaire comme un document sur un disque ... tout en un dans un document est rapide. En outre, le document est structuré de sorte que vous puissiez extraire rapidement une seule chose. D'autre part, rechercher dans tous les documents des éléments correspondant à un attribut particulier peut avoir des performances moindres (comparer avec "grep" contre tous les fichiers) ... c'est tout un compromis.

Une autre approche serait LDAP, dans laquelle on disposerait d'une base avec tous les éléments associés, mais on appliquerait également des classes d'objet supplémentaires pour les autres types d'éléments. (voir Inventaire du système avec LDAP )

Une fois que vous empruntez ce chemin, vous pouvez trouver quelque chose qui correspond exactement à ce que vous recherchez ... même si tout est assorti de compromis.


10

6 ans plus tard

Maintenant que JSON dans Postgres est arrivé, nous avons une autre option, pour ceux qui utilisent Postgres. Si vous souhaitez uniquement attacher 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-votre-next-json-database/ .

Notez que Postgres stocke réellement JSONB, et non JSON en texte brut, et prend en charge les index sur les champs d’un document / champ JSONB, au cas où vous découvririez que vous souhaitiez 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 au modèle EAV, qui devrait être envisagée par quiconque réfléchit à la question initiale.


3
Je pense que c'est une bonne idée de poster une solution alternative. Pour garder les autres sur la bonne voie, MS SQL prenait en charge les colonnes XML avec la possibilité de les indexer pendant un certain temps et pouvait faire de même avec JSON à partir de 2016 (bien que JSON ne soit pas un type de colonne natif dans MS SQL, vous pouvez toujours l'indexer. ) D'autre part, d'après ce que j'ai lu, le support JSON de Postgres est préférable. Par exemple, il semblerait qu'il prenne en charge les index sur les données dans les propriétés du tableau JSON.
Giedrius

1
"... les champs d'un champ JSONB ne peuvent pas être modifiés individuellement avec une requête UPDATE; vous devez remplacer tout le contenu du champ JSONB." C'est obsolète, n'est-ce pas? Il existe une jsonb_set()fonction dans Postgres 9.5 et versions ultérieures qui correspond exactement à cela. (L'article que vous avez lié à des liens renvoie à un article plus récent concernant les ajouts de fonctionnalités 9.5 .)
Wildcard

7

Généralement, les gens regardent autrement si vous l'utilisez pour des tables de recherche ou dans d'autres situations où il est avantageux 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 du stockage de données disparates dans une longue table mince ... Vous ne devriez pas avoir peur de créer de nouvelles tables si vous en avez besoin, et avoir juste une ou deux longues tables maigres n’est pas bien mieux que de ne deux courtes tables de graisse.

Cela dit, je suis notoire pour l’utilisation de tables EAV pour la journalisation. Ils ont une bonne utilité.


Veuillez définir "table maigre" et "table grasse".
Tulains Córdova

@ TulainsCórdova: Une table "maigre" serait une table avec quelques lignes et plusieurs colonnes, tandis qu'une table grasse en serait une avec plusieurs colonnes et quelques lignes. Un exemple consisterait à créer une table de recherche contenant des propriétés pour des livres, par exemple. Une table fat aurait un enregistrement par livre, avec plusieurs colonnes pour des éléments de données spécifiques, tandis qu'une table mince aurait peut-être quatre colonnes id, book, nom_zone, nom_zone. Le premier avantage est qu'il y a moins d'enregistrements, mais que certains champs peuvent être vides et que tout est plus difficile à étendre.
Satanicpuppy 10/02/2017

@Satanicpuppy Je pense que vos définitions maigres / grasses sont mélangées - elles sont identiques. Voulez-vous dire qu'une table maigre a peu de colonnes et beaucoup de lignes?
Charles Wood

1

EAV change 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 sous-entendez que les colonnes A et B forment un tableau X. C'est l'inverse en un sens, mais il n'y a pas nécessairement de mappage un à un. Vous pourriez dire que A et B correspondent tous deux à des tables (ou types) X et Y. Cela pourrait être important dans le domaine plus impliqué où le contexte est important.

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 à ce que vous devriez en faire (pas que vous ne puissiez pas le faire).

Je suis d'accord avec EAV pour dire que EAV serait lent ou "te donner assez de corde pour te pendre". Au lieu de cela, je mettrais davantage l'accent sur les points forts d'EAV et si cela convient à votre espace de problèmes, vous devriez l'examiner.

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

Le problème avec EAV a été dans mon esprit dû à l’absence d’une implémentation telle que Datomic. Comme il s’agit d’une question sur EAV, je ne veux pas en parler à propos de Datomic, mais c’est une de ces choses où je pense qu’ils ont tout bien compris en ce qui concerne EAV.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.