EAV: ¿es realmente malo en todos los escenarios?

65

Estoy pensando en usar un modelo de entidad-atributo-valor (EAV) para algunas de las cosas en uno de los proyectos, pero todas las preguntas al respecto en Stack Overflow terminan en respuestas que llaman a EAV un antipatrón.

Pero me pregunto si es así de malo en todos los casos.

Digamos que la entidad del producto de la tienda, tiene características comunes, como el nombre, la descripción, la imagen y el precio, que participan en la lógica de muchos lugares y tiene características (semi) únicas, como el reloj y la pelota de playa, que se describirían por aspectos completamente diferentes. Así que creo que EAV encajaría para almacenar esas características (semi) únicas.

Todo esto supone que, para mostrar la lista de productos, hay suficiente información en la tabla de productos (eso significa que no hay ningún EAV involucrado) y solo cuando se muestra un producto / se comparan hasta 5 productos / etc. Se utilizan los datos guardados con EAV.

He visto tal enfoque en el comercio de Magento y es bastante popular, entonces, ¿hay casos en que EAV es razonable?

Giedrius
fuente
2
@busy_wait Tablas "Entity-Attibute-Value" - vea el modelo Entity-attribute-value en Wikipedia .
Ross Patterson
Para ver un ejemplo del patrón EAV que funciona realmente bien, eche un vistazo a la base de datos Datomic. Almacena todo en el patrón EAVT (T es una "marca de tiempo", en realidad más como una identificación de transacción). Su [documentación de indexación] (docs.datomic.com/indexes.html) parece mostrarlo mejor. Para ver un ejemplo de EAV funcionando terriblemente, vea Wordpress .
Dan Ross

Respuestas:

81

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

EAV le da flexibilidad al desarrollador para definir el esquema según sea necesario y esto es bueno en algunas circunstancias.

Por otro lado, funciona muy mal en el caso de una consulta mal definida y puede soportar otras malas prácticas.

En otras palabras, EAV te da suficiente cuerda para ahorcarte y en esta industria, las cosas deben diseñarse con el nivel más bajo de complejidad porque el tipo que te reemplaza en el proyecto probablemente sea un idiota.

árbol de arce
fuente
32
Amo la última oración.
Zohar Peled
2
Enlace podrido. ¿Hay una versión en caché en alguna parte?
Comodín
1
No sigas el enlace. La página se carga lentamente y no es útil. Además, los foros de estilo antiguo como ese apestan. ¡Use el desbordamiento de pila en su lugar! Vota respuestas buenas / útiles y tira la basura.
Jess
29

En pocas palabras, EAV es útil cuando su lista de atributos crece con frecuencia, o cuando es tan grande que la mayoría de las filas se llenarían en su mayoría con NULL si convirtiera cada atributo en una columna. Se convierte en un antipatrón cuando se usa fuera de ese contexto.

Karl Bielefeldt
fuente
16
Reemplazaría "con frecuencia" por "necesita la posibilidad de cambiar en tiempo de ejecución".
Doc Brown
3
Podemos acortar aún más ese Doc Brown usando la palabra "dinámica" bastante bien entendida: EAV es útil cuando su lista de atributos puede cambiar dinámicamente.
Alexander Mills
Incluso más allá de "cuando sus atributos pueden cambiar" - "dinámicamente" es un poco redundante en este contexto :)
Wranorn
1
¿Es necesariamente más útil que, digamos, tener la forma de cambiar un atributo para realizar un CREATE TABLEnuevo atributo?
Damian Yerrick
@DamianYerrick enfoque interesante. ¿Has usado esto en producción?
excavación
21

Digamos que la entidad del producto de la tienda, tiene características comunes, como nombre, descripción, imagen, precio, etc., que participan en la lógica de muchos lugares y tiene características (semi) únicas, como el reloj y la pelota de playa que se describirían por aspectos completamente diferentes. . ¿Entonces creo que EAV encajaría para almacenar esas características (semi) únicas?

El uso de una estructura EAV tiene varias implicaciones que son compensaciones.

Está intercambiando un 'menos espacio para la fila porque no tiene 100 columnas que están null' en contra 'de consultas y modelos más complejos'.

Tener un EAV generalmente significa que el valor es una cadena en la que se pueden introducir datos. Esto tiene implicaciones en la validez y la verificación de restricciones. Considere la situación en la que ha puesto la cantidad de baterías usadas como algo en la tabla EAV. Desea encontrar una linterna que use baterías de tamaño C, pero menos de 4 de ellas.

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

Lo que debe darse cuenta aquí es que no puede usar un índice razonablemente en el valor. Tampoco puede evitar que alguien ingrese algo que no sea un número entero allí, o un número entero no válido (usa baterías '-1') porque la columna de valor se usa una y otra vez para diferentes propósitos.

Esto tiene implicaciones al tratar de escribir un modelo para el producto. Tendrás los buenos valores mecanografiados ... pero también vas a tener una Map<String,String>sesión allí con todo tipo de cosas . Esto tiene implicaciones adicionales cuando se serializa a XML o Json y las complejidades de tratar de validar o realizar consultas en esas estructuras.

Algunas alternativas o modificaciones al patrón a considerar es en lugar de una clave de forma libre, para tener otra tabla con claves válidas. Significa que, en lugar de hacer comparaciones de cadenas en la base de datos, está comprobando la igualdad de los identificadores de clave externa. Cambiar la clave en sí se realiza en un solo lugar. Tienes un conjunto de claves conocido, lo que significa que se pueden hacer como una enumeración.

También podría tener tablas relacionadas que contengan atributos de una clase específica de producto. Un departamento de abarrotes podría tener otra tabla que tenga varios atributos asociados que los materiales de construcción no necesitan (y viceversa).

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

Hay momentos que requieren especialmente una tabla EAV.

Considere la situación en la que no solo está escribiendo un sistema de inventario para su empresa donde conoce cada producto y cada atributo. Ahora está escribiendo un sistema de inventario para vender a otras compañías. No puede conocer todos los atributos de cada producto; deberán definirlos.

Una idea que surge es "vamos a dejar que el cliente modifican la mesa", y esto es sólo una mala (de entrar en meta-programación para las estructuras de tabla porque ya no sabe lo que es el lugar donde, que pueden regiamente desordenar la estructura o está dañado la aplicación, tienen acceso para hacer cosas incorrectas y las implicaciones de ese acceso se vuelven significativas). Hay más sobre esta ruta en MVC4: ¿Cómo crear un modelo en tiempo de ejecución?

En su lugar, crea la interfaz administrativa para una tabla EAV y permite que se use. Si el cliente desea crear una entrada para 'polkadots', entra en la tabla EAV y ya sabe cómo lidiar con eso.

Un ejemplo de esto se puede ver en el modelo de base de datos para Redmine , puede ver la tabla custom_fields y la tabla custom_values, que son partes del EAV que permiten extender el sistema.


Tenga en cuenta que si encuentra que toda la estructura de su tabla se parece a EAV en lugar de relacional, es posible que desee ver el sabor KV de NoSQL (cassandra, redis, Mongo, ...). Tenga en cuenta que a menudo vienen con otras compensaciones en su diseño que pueden o no ser apropiadas para lo que lo está utilizando. Sin embargo, están diseñados específicamente con la intención de una estructura EAV.

Es posible que desee leer SQL vs NoSQL para un sistema de gestión de inventario

Siguiendo este enfoque con una base de datos NoSQL orientada a documentos (couch, mongo), podría considerar que cada elemento del inventario es un documento en un disco ... extraer todo en un solo documento es rápido. Además, el documento está estructurado para que pueda extraer cualquier cosa rápidamente. Por otro lado, buscar en todos los documentos cosas que coincidan con un atributo particular puede tener un menor rendimiento (comparar usando 'grep' contra todos los archivos) ... todo es una compensación.

Otro enfoque sería LDAP, donde uno tendría una base con todos sus elementos asociados, pero luego también se le aplicarían clases de objetos adicionales para los otros tipos de elementos. (ver Inventario del sistema con LDAP )

Una vez que siga este camino, puede encontrar algo que coincida exactamente con lo que está buscando ... aunque todo viene con algunas compensaciones.

Comunidad
fuente
10

6 años despues

Ahora que JSON en Postgres está aquí, tenemos otra opción, para aquellos que usan Postgres. Si solo desea adjuntar algunos datos adicionales a un producto, entonces sus necesidades son bastante simples. Ejemplo:

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

Aquí hay una introducción más sencilla a JSON en Postgres: https://www.compose.com/articles/is-postgresql-your-next-json-database/ .

Tenga en cuenta que Postgres realmente almacena JSONB, no JSON de texto sin formato, y admite índices en campos dentro de un documento / campo JSONB, en caso de que descubra que realmente desea consultar esos datos.

Además, tenga en cuenta que los campos dentro de un campo JSONB no pueden modificarse individualmente con una consulta ACTUALIZAR; tendría que reemplazar todo el contenido del campo JSONB.

Es posible que esta respuesta no aborde directamente la pregunta, pero ofrece una alternativa a un patrón EAV, que debe ser considerada por cualquiera que esté reflexionando sobre la pregunta original.

Dan Ross
fuente
3
Creo que es una buena idea publicar una solución alternativa. Solo para mantener a otros en camino, MS SQL admitía columnas XML con la capacidad de indexarlas por un tiempo y, a partir de 2016, puede hacer lo mismo con JSON (aunque JSON no es un tipo de columna nativa en MS SQL, aún puede indexarlo ) Por otro lado, por lo que leí, el soporte de Postgres JSON es mejor, por ejemplo, parece que admite índices de datos en propiedades de matriz JSON.
Giedrius
1
"... los campos dentro de un campo JSONB no se pueden modificar individualmente con una consulta de ACTUALIZACIÓN; tendría que reemplazar todo el contenido del campo JSONB". Esto está desactualizado, ¿no? Hay una jsonb_set()función en Postgres 9.5 y posterior que es exactamente para esto. (El artículo que vinculó a los enlaces a su vez a un artículo más nuevo que discute las adiciones de la característica 9.5 .)
Comodín el
7

Por lo general, las personas miran para otro lado si lo está utilizando para tablas de búsqueda u otras situaciones en las que el beneficio es evitar tener que crear tablas para uno o dos valores almacenados. La situación que está describiendo, donde básicamente está almacenando propiedades de elementos, suena perfectamente normal (y normalizada). Ampliar una tabla para almacenar un número variable de atributos de elementos es una mala idea.

Para el caso general de almacenar datos dispares en una tabla larga y delgada ... No debe tener miedo de crear nuevas tablas si es necesario, y tener solo una o dos tablas largas y delgadas no es mucho mejor que tener solo una o Dos mesas cortas y gordas.

Dicho esto, soy conocido por usar tablas EAV para iniciar sesión. Tienen alguna buena utilidad.

Satanicpuppy
fuente
Defina "tabla delgada" y "tabla gorda".
Tulains Córdova
@ TulainsCórdova: Una tabla "delgada" sería una con pocas filas y muchas columnas, mientras que una tabla gruesa es una con muchas columnas y pocas filas. Un ejemplo sería construir una tabla de búsqueda donde tenga propiedades para, por ejemplo, libros. Una tabla gruesa tendría un registro por libro, con muchas columnas para datos específicos, mientras que una tabla delgada tendría quizás cuatro columnas id, book, field_name, field_data. La ventaja del primero es que hay menos registros, pero lo negativo es que algunos campos pueden estar en blanco, y todo es más difícil de extender.
Satanicpuppy
@Satanicpuppy Creo que tus definiciones flacas / gordas están mezcladas, son lo mismo. ¿Quiere decir que una mesa delgada tiene pocas columnas y muchas filas?
Charles Wood
1

EAV cambia el problema de la estructura explícita a la percepción implícita. En lugar de decir que X es una tabla con las columnas A y B. Usted implica que las columnas A y B forman la tabla X. Es al revés en un sentido, pero no necesariamente hay un mapeo uno a uno. Se podría decir que A y B se asignan a la tabla (o tipo) X e Y. Esto podría ser importante en el dominio más involucrado donde el contexto es importante.

He estado estudiando Datomic para este tipo de enfoque y creo que es un sistema muy útil y poderoso con límites sobre lo que debe hacer con él (no es que no pueda).

Que EAV sería lento, o "darte suficiente cuerda para ahorcarte" no es una declaración con la que estoy de acuerdo. Más bien, pondría más énfasis en las fortalezas de EAV y si se adapta a su espacio problemático, debería considerarlo.

Mi experiencia es que es un maravilloso enfoque casi ilimitado para el modelado. Específicamente, en el caso de Datomic, imponen un conjunto semántico por encima de todo. Cualquier decisión de modelado que modele una relación puede ir libremente de una a muchas sin tener que rediseñar columnas / tablas. También puede retroceder siempre que la restricción no viole la invariante. Todo es lo mismo debajo del capó.

En mi opinión, el problema con EAV ha sido la falta de una implementación como Datomic. Dado que esta es una pregunta sobre EAV, no quiero hablar sobre Datomic, pero es una de esas cosas en las que creo que hicieron todo bien con respecto a EAV.

John Leidegren
fuente