mysql - español - rdbms examples
Cómo almacenar datos con un número dinámico de atributos en una base de datos (7)
Tengo una serie de objetos diferentes con un número variable de atributos. Hasta ahora, he guardado los datos en archivos XML que permiten un número de atributos en constante cambio. Pero estoy tratando de moverlo a una base de datos.
¿Cuál sería su forma preferida de almacenar estos datos?
Algunas estrategias que he identificado hasta ahora:
- Tener un solo campo llamado "atributos" en la tabla del objeto y almacenar los datos serializados o json''ed allí.
- Almacenar los datos en dos tablas (objetos, atributos) y usar una tercera para guardar las relaciones, por lo que es una verdadera relación n: m. Solución muy limpia, pero posiblemente muy costosa para obtener un objeto completo y todos sus atributos
- Identificando los atributos que todos los objetos tienen en común y creando campos para estos en la tabla del objeto. Almacene los atributos restantes como datos serializados en otro campo. Esto tiene una ventaja sobre la primera estrategia, facilitando las búsquedas.
¿Algunas ideas?
Permítanme dar algo de concreción a lo que DVK estaba diciendo.
Asumiendo que los valores son del mismo tipo que la tabla se vería (buena suerte, creo que la va a necesitar):
dynamic_attribute_table ------------------------ id NUMBER key VARCHAR value SOMETYPE?
ejemplo (coches):
|id| key | value | --------------------------- | 1|''Make'' |''Ford'' | | 1|''Model'' |''Edge'' | | 1|''Color'' |''Blue'' | | 2|''Make'' |''Chevrolet''| | 2|''Model'' |''Malibu'' | | 2|''MaxSpeed''|''110mph'' |
Así,
entidad 1 = {(''Hacer'', ''Ford''), (''Modelo'', ''Borde''), (''Color'', ''Azul'')}
y,
entidad 2 = {(''Hacer'', ''Chevrolet''), (''Modelo'', ''Malibu''), (''MaxSpeed'', ''110mph'')}.
Si alguna vez planea buscar atributos específicos, es una mala idea serializarlos en una sola columna, ya que tendrá que usar las funciones por fila para obtener la información, esto nunca se adapta bien.
Yo optaría por tu segunda opción. Tenga una lista de atributos en una tabla de atributos, los objetos en su propia tabla y una tabla de relación muchos a muchos llamada atributos de objeto.
Por ejemplo:
objects:
object_id integer
object_name varchar(20)
primary key (object_id)
attributes:
attr_id integer
attr_name varchar(20)
primary key (attr_id)
object_attributes:
object_id integer references (objects.object_id)
attr_id integer references (attributes.attr_id)
oa_value varchar(20)
primary key (object_id,attr_id)
Se nota su preocupación por el rendimiento pero, según mi experiencia, siempre es más costoso dividir una columna que combinar varias columnas. Si resulta que hay problemas de rendimiento, es perfectamente aceptable romper 3NF por razones de rendimiento.
En ese caso, lo almacenaría de la misma manera pero también tendría una columna con los datos serializados sin procesar. Siempre que use los activadores de inserción / actualización para mantener sincronizados los datos de columnas y combinados, no tendrá ningún problema. Pero no debes preocuparte por eso hasta que surja un problema real.
Al usar esos disparadores, minimiza el trabajo requerido solo cuando los datos cambian. Al tratar de extraer información de sub-columnas, hace un trabajo innecesario en cada selección.
Si está utilizando una base de datos relacional, creo que hizo un buen trabajo al enumerar las opciones. Cada uno tiene sus pros y sus contras. USTED está en la mejor posición para decidir qué funciona mejor para sus circunstancias.
El enfoque serializado es probablemente el más rápido (dependiendo de su código para la deserialización), pero significa que no podrá consultar los datos con SQL. Si dice que no necesita consultar los datos con SQL, entonces estoy de acuerdo con @longneck, tal vez debería usar un db de estilo clave / valor en lugar de un db relacional.
EDITAR - leyendo más de sus comentarios, POR QUÉ está cambiando a db si la velocidad es su principal preocupación. ¿Qué hay de malo en tu implementación actual de XML?
Si va a editar / manipular / eliminar los atributos en un punto posterior, hacer una verdadera n: m (segunda opción) será la que busco. (O intente convertirla en una tabla 2 donde se repita el mismo atributo. Pero el tamaño de los datos será alto)
Si no está tratando con atributos (solo está capturando y mostrando los datos), puede continuar y almacenar en un campo con algún separador (asegúrese de que el separador no aparezca en el valor del atributo)
Solía implementar este esquema :
t_class (id RAW(16), parent RAW(16)) -- holds class hierachy.
t_property (class RAW(16), property VARCHAR) -- holds class members.
t_declaration (id RAW(16), class RAW(16)) -- hold GUIDs and types of all class instances
t_instance (id RAW(16), class RAW(16), property VARCHAR2(100), textvalue VARCHAR2(200), intvalue INT, doublevalue DOUBLE, datevalue DATE) -- holds ''common'' properties
t_class1 (id RAW(16), amount DOUBLE, source RAW(16), destination RAW(16)) -- holds ''fast'' properties for class1.
t_class2 (id RAW(16), comment VARCHAR2(200)) -- holds ''fast'' properties for class2
--- etc.
RAW(16)
es donde Oracle
tiene GUID
s
Si desea seleccionar todas las propiedades para un objeto, emita:
SELECT i.*
FROM (
SELECT id
FROM t_class
START WITH
id = (SELECT class FROM t_declaration WHERE id = :object_id)
CONNECT BY
parent = PRIOR id
) c
JOIN property p
ON p.class = c.id
LEFT JOIN
t_instance i
ON i.id = :object_id
AND i.class = p.class
AND i.property = p.property
t_property
contiene cosas que normalmente no buscas (como, descripciones de texto, etc.)
Las propiedades rápidas son, de hecho, tablas normales que tiene en la base de datos, para que las consultas sean eficientes. Tienen valores solo para las instancias de una determinada clase o sus descendientes. Esto es para evitar uniones extra.
No tiene que usar tablas rápidas y limitar todos sus datos a estas cuatro tablas.
Suena como si necesitas algo lamer couchdb , no un RDBMS.
Una variación en su solución 2d es solo dos tablas (asumiendo que todos los atributos son de un solo tipo):
T1: | Columnas de datos de objeto | Object_id |
T2: | ID de objeto | nombre_atributo | valor de atributo | (índice único en las 2 primeras columnas)
Esto es aún más eficiente cuando se combina con la tercera solución, por ejemplo, todos los campos comunes entran en T1.
No se recomienda rellenar> 1 atributo en el mismo blob: no puede filtrar por atributos, no puede actualizarlos eficientemente