Base de datos de valor de atributo de entidad versus comercio electrónico de modelo relacional estricto

136

Es seguro decir que el modelo de base de datos EAV / CR es malo. Dicho eso

Pregunta: ¿Qué modelo de base de datos, técnica o patrón debería usarse para tratar con "clases" de atributos que describen productos de comercio electrónico que se pueden cambiar en tiempo de ejecución?

En una buena base de datos de comercio electrónico, almacenará clases de opciones (como la resolución de TV y luego tendrá una resolución para cada TV, pero el siguiente producto puede no ser un TV y no tener "resolución de TV"). ¿Cómo los almacena, busca eficientemente y permite a sus usuarios configurar tipos de productos con campos variables que describen sus productos? Si el motor de búsqueda descubre que los clientes suelen buscar televisores en función de la profundidad de la consola, puede agregar la profundidad de la consola a sus campos, y luego agregar una sola profundidad para cada tipo de producto de televisión en tiempo de ejecución.

Hay una buena característica común entre las buenas aplicaciones de comercio electrónico donde muestran un conjunto de productos, luego tienen menús laterales "detallados" donde puede ver "Resolución de TV" como encabezado, y las cinco Resoluciones de TV más comunes para conjunto encontrado Hace clic en uno y solo muestra televisores de esa resolución, lo que le permite profundizar aún más seleccionando otras categorías en el menú lateral. Estas opciones serían los atributos dinámicos del producto agregados en tiempo de ejecución.

Más discusión:

En resumen, ¿hay algún enlace en Internet o descripciones de modelos que puedan arreglar "académicamente" la siguiente configuración? Agradezco a Noel Kennedy por sugerir una tabla de categorías, pero la necesidad puede ser mayor que eso. Lo describo de una manera diferente a continuación, tratando de resaltar el significado. Es posible que necesite una corrección del punto de vista para resolver el problema, o puede que necesite profundizar en el EAV / CR.

Me encanta la respuesta positiva al modelo EAV / CR. Mis colegas desarrolladores dicen lo que Jeffrey Kemp mencionó a continuación: "las nuevas entidades deben ser modeladas y diseñadas por un profesional" (fuera de contexto, lea su respuesta a continuación). El problema es:

  • las entidades agregan y eliminan atributos semanalmente
    (las palabras clave de búsqueda determinan los atributos futuros)
  • nuevas entidades llegan semanalmente
    (los productos se ensamblan a partir de piezas)
  • las entidades antiguas desaparecen semanalmente
    (archivadas, menos populares, estacionales)

El cliente desea agregar atributos a los productos por dos razones:

  • departamento / búsqueda de palabras clave / tabla de comparación entre productos similares
  • configuración del producto de consumo antes del pago

Los atributos deben tener importancia, no solo una búsqueda de palabras clave. Si quieren comparar todos los pasteles que tienen un "glaseado de crema batida", pueden hacer clic en pasteles, hacer clic en el tema del cumpleaños, hacer clic en el glaseado de crema batida, luego verificar todos los pasteles que sean interesantes sabiendo que todos tienen glaseado de crema batida. Esto no es específico para pasteles, solo un ejemplo.

Zachary Scott
fuente
¿Por qué no puede simplemente tener una tabla de 'categoría' con una clave externa que se refiere a sí misma?
Noel Kennedy
29
No es seguro, ni preciso, decir que el modelo de base de datos EAV es malo, porque es muy adecuado para algunas aplicaciones.
spencer7593
¿Qué sucede si decora varios objetos con varias propiedades, heredando de un padre como en Entity Framework 4? ¿Cómo persiste esos objetos?
Zachary Scott
1
Volviendo a señalar este excelente artículo sobre la experiencia de un consultor con un sistema basado en una versión extrema de EAV. Léelo! simple-talk.com/opinion/opinion-pieces/bad-carma
Jeffrey Kemp
1
EAV es un modelo de base de datos muy viable. Estoy trabajando en un problema similar como tú y la solución es EAV. Recomendaría el siguiente artículo: sqlblog.com/blogs/aaron_bertrand/archive/2009/11/19/…
Sandor

Respuestas:

75

Hay algunos pros y contras generales en los que puedo pensar, hay situaciones en las que una es mejor que la otra:

Opción 1, modelo EAV:

  • Pro: menos tiempo para diseñar y desarrollar una aplicación simple
  • Pro: nuevas entidades fáciles de agregar (¿podrían incluso agregarlas los usuarios?)
  • Pro: componentes de interfaz "genéricos"
  • Con: código complejo requerido para validar tipos de datos simples
  • Con: SQL mucho más complejo para informes simples
  • Con: los informes complejos pueden volverse casi imposibles
  • Con: pobre rendimiento para grandes conjuntos de datos

Opción 2, Modelar cada entidad por separado:

  • Con: más tiempo requerido para reunir los requisitos y el diseño
  • Con: las nuevas entidades deben ser modeladas y diseñadas por un profesional
  • Con: componentes de interfaz personalizados para cada entidad
  • Pro: restricciones de tipo de datos y validación simples de implementar
  • Pro: SQL es fácil de escribir, fácil de entender y depurar
  • Pro: incluso los informes más complejos son relativamente simples
  • Pro: el mejor rendimiento para grandes conjuntos de datos

Opción 3, Combinación (modelar entidades "correctamente", pero agregar "extensiones" para atributos personalizados para algunas / todas las entidades)

  • Pro / Con: más tiempo requerido para reunir los requisitos y el diseño que la opción 1, pero quizás no tanto como la opción 2 *
  • Con: las nuevas entidades deben ser modeladas y diseñadas por un profesional
  • Pro: nuevos atributos pueden agregarse fácilmente más adelante
  • Con: código complejo requerido para validar tipos de datos simples (para los atributos personalizados)
  • Contras: aún se requieren componentes de interfaz personalizados, pero los componentes de interfaz genéricos pueden ser posibles para los atributos personalizados
  • Con: SQL se vuelve complejo tan pronto como se incluye cualquier atributo personalizado en un informe
  • Contras: buen rendimiento en general, a menos que comience a buscar o informar por los atributos personalizados

* No estoy seguro de si la Opción 3 necesariamente ahorraría tiempo en la fase de diseño.

Personalmente, me inclinaría hacia la opción 2 y evitaría EAV siempre que sea posible. Sin embargo, para algunos escenarios los usuarios necesitan la flexibilidad que viene con EAV; Pero esto tiene un gran costo.

Jeffrey Kemp
fuente
¿Qué pasaría si tuviera una sola tabla con índices para los valores de texto 1-n, luego en C # (en ram) asigne lo que desea a lo que necesita? Seguiría funcionando como un EAV, pero las "coincidencias" serían modelos de dominio. Algo así como una serialización, pero podría usar selecciones de SQL en campos de texto indexados. No hay selecciones múltiples por registro. Todo el "costo" sucede en la RAM.
Zachary Scott
1
@ Zim, eso suena más o menos como la opción 3. Cada fila tiene 1-n columnas "genéricas" adicionales, y los datos almacenados en ellas se interpretan a nivel de aplicación. Obtiene el beneficio de rendimiento de tener todos los datos para un registro en un solo lugar. Sin embargo, los metadatos sobre esas columnas deben almacenarse en algún lugar, y aquí es donde el costo se arrastra. Claro, podemos almacenar en caché los metadatos en RAM, pero aún cuesta más que modelar el dominio directamente en el código de la aplicación. Sin embargo, ¡sin duda mejor que un modelo EAV completo!
Jeffrey Kemp
1
+10000 Gran respuesta. Hoy en día la gente escatima en el diseño de bases de datos y la recopilación de requisitos. Prefieren escribir cien veces más líneas de código, que se toman el tiempo para hacer un buen diseño.
Tulains Córdova
No necesita más diseño para la opción relacional (2) que la opción EAV (1) si solo proporciona la estructura de la opción 1. Y la interfaz relacional es genérica a partir de metadatos que describen esa estructura. Esto elimina toda la opción 2 Contras. Sin embargo, olvidó que el único Con: DDL real puede ser demasiado lento para administrar tablas.
Filipinas
Hola @philipxy, no dije "más diseño". La razón de ser del EAV es que (presumiblemente) el diseñador del sistema puede dedicar menos tiempo al diseño del modelo, dejando este trabajo de diseño a "usuarios" más adelante (esta falta de diseño profesional lleva a los Contras enumerados para la Opción 1) . Si el EAV no genera ahorros para el diseñador, eso solo agrega más combustible al fuego por rechazar el EAV sin control. Además, no estoy de acuerdo con que el DDL sea "demasiado lento", ya que solo debería requerirse en raras ocasiones (es decir, para corregir errores en el modelo o para implementar nuevas funciones), su rendimiento debería ser relativamente poco importante.
Jeffrey Kemp el
63

Es seguro decir que el modelo de base de datos EAV / CR es malo.

No, no es. Es solo que son un uso ineficiente de las bases de datos relacionales. Una tienda puramente clave / de valor funciona muy bien con este modelo.

Ahora, a su pregunta real: ¿Cómo almacenar varios atributos y mantenerlos disponibles para búsquedas?

Solo usa EAV. En su caso, sería una sola mesa extra. indexarlo tanto en el nombre como en el valor del atributo, la mayoría de los RDBM usarían compresión de prefijo en las repeticiones del nombre del atributo, lo que lo hace realmente rápido y compacto.

EAV / CR se pone feo cuando lo usas para reemplazar campos 'reales'. Como con todas las herramientas, el uso excesivo es 'malo' y le da una mala imagen.

Javier
fuente
así que la pregunta es que tengo 15 campos adicionales para una de mis categorías y en cada modelo requiere 16 unirse + tabla principal, por lo que tengo 16 uniones restantes para buscar productos (y tener 16 donde si el cliente lo desea) en 3-4 millones de registros ( un sitio web para la venta de productos de segunda mano por personas) por lo que tiene un bajo rendimiento?
babak faghihian
2
Si estos "campos adicionales" ya están definidos, definitivamente sería mejor hacerlo como "campos reales". Y, por supuesto, hacer un número ilimitado de uniones en una consulta grande sería una gran carga (¡pero aún podría estar bien!). Lo que he hecho en un proyecto con muchos metadatos es permitir cualquier número de "etiquetas" (como registros EAV) por "elemento principal", pero la "consulta grande" solo selecciona algunos nombres de etiquetas predefinidos, manteniendo limitado el número total de uniones (actualmente típica está a sólo 4 etiquetas y otra alrededor de 5 une), y cuando el usuario selecciona un elemento específico, entonces se fetchs todo lo relacionado, pero para un solo elemento.
Javier
pero, por supuesto, ese sistema específico se está transfiriendo actualmente a un hstorecampo (solo una de las razones por las que usamos PostgreSQL)
Javier
15
// En este punto, me gustaría tomar un momento para hablarles sobre el formato Magento / Adobe PSD .
// Magento / PSD no es una buena plataforma / formato de comercio electrónico . Magento / PSD ni siquiera es una mala plataforma / formato de comercio electrónico . Llamarlo así sería un
// insultar a otras plataformas / formatos de comercio electrónico defectuosos , como Zencart u OsCommerce. No, Magento / PSD es una plataforma / formato de comercio electrónico abismal . Teniendo
// trabajé en este código durante varias semanas, mi odio por Magento / PSD se ha convertido en un fuego furioso
// que arde con la feroz pasión de un millón de soles.

http://code.google.com/p/xee/source/browse/trunk/XeePhotoshopLoader.m?spec=svn28&r=11#107

Los modelos internos son extravagantes en el mejor de los casos, como si alguien pusiera el esquema en un juego alucinante, lo sellara y lo pusiera en un shacker de pintura ...

Mundo real: estoy trabajando en una aplicación de cumplimiento de midware y aquí hay una de las consultas para obtener información de la dirección.

CREATE OR REPLACE VIEW sales_flat_addresses AS
SELECT sales_order_entity.parent_id AS order_id, 
       sales_order_entity.entity_id, 
       CONCAT(CONCAT(UCASE(MID(sales_order_entity_varchar.value,1,1)),MID(sales_order_entity_varchar.value,2)), "Address") as type, 
       GROUP_CONCAT( 
         CONCAT( eav_attribute.attribute_code," ::::: ", sales_order_entity_varchar.value )
         ORDER BY sales_order_entity_varchar.value DESC
         SEPARATOR '!!!!!' 
       ) as data
  FROM sales_order_entity
       INNER JOIN sales_order_entity_varchar ON sales_order_entity_varchar.entity_id = sales_order_entity.entity_id
       INNER JOIN eav_attribute ON eav_attribute.attribute_id = sales_order_entity_varchar.attribute_id
   AND sales_order_entity.entity_type_id =12
 GROUP BY sales_order_entity.entity_id
 ORDER BY eav_attribute.attribute_code = 'address_type'

Información de dirección exacta para un pedido, perezosamente

-

Resumen: solo use Magento si:

  1. Te dan grandes sacos de dinero
  2. Debes
  3. Disfruta el dolor
Vee
fuente
Esta es una publicación anterior, pero desearía haberla encontrado hace 3 meses cuando comencé un proyecto de Magento para un cliente. ¡+1 para la analogía de boggle / paint-shaker!
trevorc
1
Bastante interesante, magento parece ser el rey de la carretera en términos de sistemas de comercio electrónico. Tal vez solo su comercialización es muy buena
Herr
1
Magento no es popular debido al nivel de mantenimiento, sino a la capacidad de personalizar, lo que permite a cualquiera implementar nuevas funciones sin cambios de arquitectura o pocas modificaciones. Esta característica tiene un costo.
Diego Mendes
Manténgase alejado de Magento 2 si desea evitar Triple Pain y más dolor en la parte superior tanto para FE como para BE
TheBlackBenzKid
15

Me sorprende que nadie haya mencionado las bases de datos NoSQL.

Nunca practiqué NoSQL en un contexto de producción (solo probé MongoDB y me impresionó), pero el objetivo de NoSQL es poder guardar elementos con atributos variables en el mismo "documento".

Lucas T
fuente
Tenga en cuenta que las escrituras en MongoDB requieren un bloqueo a nivel de base de datos y lo que eso significa para el tráfico de producción concurrente.
Bill Karwin
Considere que la duración del bloqueo es del orden de microsegundos.
Hola mundo, el
12

Cuando el rendimiento no es un requisito importante, como en un tipo de aplicación ETL, EAV tiene otra ventaja: los ahorros diferenciales.

He implementado una serie de aplicaciones en las que un requisito general era la capacidad de ver el historial de un objeto de dominio desde su primera "versión" hasta su estado actual. Si ese objeto de dominio tiene una gran cantidad de atributos, eso significa que cada cambio requiere que se inserte una nueva fila en su tabla correspondiente (no una actualización porque el historial se perdería, sino una inserción). Digamos que este objeto de dominio es una Persona, y tengo 500k Personas para rastrear con un promedio de más de 100 cambios durante el ciclo de vida de las Personas a varios atributos. Combine eso con el hecho de que es rara la aplicación que tiene solo 1 objeto de dominio principal y rápidamente supondrá que el tamaño de la base de datos crecería rápidamente fuera de control.

Una solución fácil es guardar solo los cambios diferenciales en los principales objetos de dominio en lugar de guardar repetidamente información redundante.

Todos los modelos cambian con el tiempo para reflejar las nuevas necesidades comerciales. Período. Usar EAV es solo una de las herramientas en nuestra caja para usar; pero nunca debe clasificarse automáticamente como "malo".

Jerry Jasperson
fuente
2
+1 para "Usar EAV no es más que una de las herramientas en nuestra caja para usar; pero nunca debe clasificarse automáticamente como" malo "".
Catchops
Por cierto, esto se llama SCD (dimensiones que cambian lentamente). También los requisitos bitemporales (un caso específico de SCD Tipo 4) requieren un esquema EAV para los atributos que tienen esta propiedad. Recuerde, el 99% de NoSQL no tiene uniones nativas, por lo que si necesita uniones "en vivo" con este tipo de datos, EAV es el único camino a seguir.
cowbert
3

Estoy luchando con el mismo problema. Puede ser interesante que consulte la siguiente discusión sobre dos soluciones de comercio electrónico existentes: Magento (EAV) y Joomla (estructura relacional regular): https://forum.virtuemart.net/index.php?topic=58686.0

Parece que el rendimiento de EAV de Magento es un verdadero espectáculo.

Por eso me estoy inclinando hacia una estructura normalizada. Para superar la falta de flexibilidad, estoy pensando en agregar un diccionario de datos separado en el futuro (XML o tablas de bases de datos separadas) que podría editarse, y en base a eso, el código de la aplicación para mostrar y comparar categorías de productos con un nuevo conjunto de atributos sería generado, junto con scripts SQL.

Tal arquitectura parece ser el punto dulce en este caso: flexible y eficiente al mismo tiempo.

El problema podría ser el uso frecuente de ALTER TABLE en el entorno en vivo. Estoy usando Postgres, por lo que su MVCC y DDL transaccional con suerte aliviarán el dolor.

aaimnr
fuente
2

Todavía voto por modelar en el nivel atómico más bajo significativo para EAV. Deje que los estándares, las tecnologías y las aplicaciones que se dirigen hacia cierta comunidad de usuarios decidan modelos de contenido, necesidades de repetición de atributos, granos, etc.

Amanda Xu
fuente
2

Si se trata solo de los atributos del catálogo de productos y, por lo tanto, los requisitos de validación para esos atributos son bastante limitados, el único inconveniente real de EAV es el rendimiento de la consulta e incluso eso es solo un problema cuando su consulta trata con múltiples "cosas" (productos) con atributos, el rendimiento de la consulta "dame todos los atributos para el producto con id 234", aunque no es óptimo, sigue siendo bastante rápido.

Una solución es usar la base de datos SQL / modelo EAV solo para el lado de administración / edición del catálogo de productos y tener algún proceso que desnormalice los productos en algo que lo haga buscable. Dado que ya tiene atributos y, por lo tanto, es bastante probable que desee facetar, este algo podría ser Solr o ElasticSearch. Este enfoque evita básicamente todas las desventajas del modelo EAV y la complejidad adicional se limita a serializar un producto completo a JSON en la actualización.

Beto
fuente
2

EAV tiene muchos inconvenientes:

  1. Degradación del rendimiento a lo largo del tiempo Una vez que la cantidad de datos en la aplicación crece más allá de cierto tamaño, es probable que la recuperación y manipulación de esos datos sea cada vez menos eficiente.
  2. Las consultas SQL son muy complejas y difíciles de escribir.
  3. Problemas de integridad de datos. No puede definir claves foráneas para todos los campos necesarios.
  4. Debe definir y mantener sus propios metadatos.
Gabriel Voinea
fuente
1. Esto también es cierto para la mayoría de las bases de datos relacionales; Por eso se inventó el fragmentación. 2. El modelado de datos puede ser complejo y difícil de implementar. He pasado semanas meses esperando cambios en el esquema de cubo OLAP. 3. Ya está hecho principalmente en software ahora 4. Debe hacer esto "en ERwin, Excel y Visio" al modelar un esquema relacional de todos modos.
cowbert
1

Tengo un problema ligeramente diferente: en lugar de muchos atributos con valores dispersos (que posiblemente sea una buena razón para usar EAV), quiero almacenar algo más como una hoja de cálculo. Las columnas en la hoja pueden cambiar, pero dentro de una hoja todas las celdas contendrán datos (no dispersos).

Hice un pequeño conjunto de pruebas para comparar dos diseños: uno con EAV y el otro con un ARRAY de Postgres para almacenar datos de la celda.

EAV ingrese la descripción de la imagen aquí

Formación ingrese la descripción de la imagen aquí

Ambos esquemas tienen índices en las columnas apropiadas, y el planificador utiliza los índices.

Resultó que el esquema basado en matriz era un orden de magnitud más rápido tanto para las inserciones como para las consultas. De las pruebas rápidas, parecía que ambas escalaban linealmente. Sin embargo, las pruebas no son muy exhaustivas. Se aceptan sugerencias y tenedores: están bajo una licencia MIT.

z0r
fuente
¿Cómo hiciste uniones en las columnas de la hoja (es decir, vlookup) con el modelo de matriz? ¿No tiene que escribir su propia función de combinación de ordenación de matriz? Dudo mucho que pueda ser tan bueno como el tipo de fusión precompilado si usó sheet_id + coordenada x + coordenada y de una celda como la clave del valor de la celda. (para emular Excel, pregenere una tabla de búsqueda para coordenadas x donde 0-18278 son columnas A-ZZZ (Excel excede el máximo en 16384)), luego puede seleccionar valores donde sheet_id = uuid y x-coord = 0 e y-coord <1001 para obtener las primeras 1000 filas de col A.
cowbert
@cowbert tienes razón; en realidad solo cargo las columnas que me interesan y hago la unión en Python. ¡Flojo!
z0r