Se llama Entity-Attribute-Value (también a veces 'pares de nombre-valor') y es un caso clásico de "una clavija redonda en un agujero cuadrado" cuando las personas usan el patrón EAV en una base de datos relacional.
Aquí hay una lista de por qué no debe usar EAV:
- No puedes usar tipos de datos. No importa si el valor es una fecha, un número o dinero (decimal). Siempre será forzado a varchar. Esto puede ser cualquier cosa, desde un problema de rendimiento menor hasta un dolor de intestino masivo (¿alguna vez tuvo que perseguir una variación de un centavo en un informe acumulativo mensual?).
- No puede (fácilmente) imponer restricciones. Se requiere una cantidad ridícula de código para imponer "Todos deben tener una altura entre 0 y 3 metros" o "La edad no debe ser nula y> = 0", a diferencia de las líneas 1-2 que cada una de esas restricciones sería en un sistema modelado adecuadamente.
- En relación con lo anterior, no puede garantizar fácilmente que obtenga la información que necesita para cada cliente (es posible que falte la edad de uno, luego el siguiente puede perder su altura, etc.). Usted puede hacerlo, pero es un infierno de mucho más difícil de lo
SELECT height, weight, age FROM Client where height is null or weight is null
.
- Relacionado de nuevo, la duplicación de datos es mucho más difícil de detectar (¿qué sucede si le dan dos edades para un cliente? Eliminar los datos, como se muestra a continuación, le dará dos filas de resultados si tiene un atributo duplicado. Si un cliente tiene dos entradas separadas para dos atributos, obtendrá cuatro filas de la consulta a continuación).
- Ni siquiera puede garantizar que los nombres de los atributos sean consistentes. "Age_yr" podría convertirse en "AGE_IN_YEARS" o "age". (Es cierto que esto no es un problema cuando recibes un extracto en comparación con cuando la gente está insertando datos, pero aún así).
- Cualquier tipo de consulta no trivial es un completo desastre. Para relacionalizar un sistema EAV de tres atributos para que pueda consultarlo de manera racional, se requieren tres combinaciones de la tabla EAV.
Comparar:
SELECT cID.ID AS [ID], cH.Value AS [Height], cW.Value AS [Weight], cA.Value AS [Age]
FROM (SELECT DISTINCT ID FROM Client) cID
LEFT OUTER JOIN
Client cW ON cID.ID = cW.ID AND cW.Metric = "Wt_kg"
LEFT OUTER JOIN
Client cH ON cID.ID = cH.ID AND cW.Metric = "Ht_cm"
LEFT OUTER JOIN
Client cA ON cID.ID = cA.ID AND cW.Metric = "Age_yr"
A:
SELECT c.ID, c.Ht_cm, c.Wt_kg, c.Age_yr
FROM Client c
Aquí hay una lista (muy corta) de cuándo debe usar EAV:
- Cuando no hay absolutamente ninguna manera de evitarlo y hay que apoyar a los datos sin esquema en su base de datos.
- Cuando solo necesita almacenar "cosas" y no espera tener que necesitarlas de una forma más estructurada. Tenga cuidado, sin embargo, el monstruo llamado "requisitos cambiantes".
Sé que acabo de pasar todo este post detallando qué EAV es una idea terrible en la mayoría de los casos - pero no son unos pocos casos donde se necesita / inevitable. sin embargo, la mayoría de las veces (incluido el ejemplo anterior), será mucho más complicado de lo que vale. Si necesita un amplio soporte para la entrada de datos de tipo EAV, debería considerar almacenarlos en un sistema de valores clave, por ejemplo, Hadoop / HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB.
Valor de atributo de entidad (EAV)
Muchos lo consideran, incluso yo, un antipatrón.
Aquí están tus alternativas:
usar herencia de tabla de base de datos
usar datos XML y funciones SQLXML
usar una base de datos nosql, como HBase
fuente
En PostgreSQL, una muy buena manera de lidiar con las estructuras EAV es el módulo adicional
hstore
, disponible para la versión 8.4 o posterior. Cito el manual:Desde Postgres 9.2 también existe el
json
tipo y una gran cantidad de funcionalidades (la mayoría se agrega con 9.3 ).Postgres 9.4 agrega el tipo de datos (¡en gran medida superior!) "JSON binario"
jsonb
a la lista de opciones. Con opciones de índice avanzadas.fuente
Si tiene una base de datos que utiliza la estructura EAV, es posible consultar los datos de varias maneras.
La respuesta de @ Simon ya muestra cómo realizar una consulta utilizando múltiples combinaciones.
Datos de muestra utilizados:
Si está utilizando un RDBMS que tiene una
PIVOT
función ( SQL Server 2005+ / Oracle 11g + ), puede consultar los datos de la siguiente manera:Ver SQL Fiddle con Demo
Si no tiene acceso a una
PIVOT
función, puede usar una función agregada con unaCASE
declaración para devolver los datos:Ver SQL Fiddle con Demo
Ambas consultas devolverán datos en el resultado:
fuente
Es divertido ver cómo el modelo EAV db es criticado e incluso considerado como un "antipatrón" por algunos.
En lo que a mí respecta, las principales desventajas son:
Sin embargo, definitivamente no debe descartar esta solución, y esta es la razón:
fuente