2009-09-18 10 views
15

Tengo varios objetos diferentes con un número variable de atributos. Hasta ahora, he guardado los datos en archivos XML que permiten un número variable de atributos. Pero estoy tratando de moverlo a una base de datos.Cómo almacenar datos con número dinámico de atributos en una base de datos

¿Cuál sería su forma preferida de almacenar estos datos?

algunas estrategias que he identificado hasta el momento:

  • Tener un único campo denominado "atributos" en la mesa del objeto y almacenar los datos serializados o json'ed allí.
  • Almacenar los datos en dos tablas (objetos, atributos) y usar un tercero para guardar las relaciones, convirtiéndola en una verdadera relación n: m. Solución muy limpia, pero posiblemente muy costosa para buscar un objeto completo y todos sus atributos
  • Identificando 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.

¿Alguna idea?

+0

¿Cuál es la motivación para pasar a una solución de db? Usted dijo abajo, esa velocidad es su principal preocupación. ¿Cree que una solución db sería más rápida que su enfoque XML actual? –

+0

Una cuarta estrategia vino a la mente con DVK proponiendo lo mismo: almacenar atributos comunes en la tabla de objetos y almacenar todos los demás usando una relación 1: n una segunda tabla. Parece el mejor compromiso para la velocidad, la flexibilidad y la solución limpia (@Tobiask) –

+0

@ Corey, no, yo no. La solución XML es increíblemente rápida en este momento y no creo que un DB pueda seguir el ritmo de eso. Es más un ejercicio para mí, intentar hacer que el sistema sea más flexible en cuanto a las opciones de almacenamiento y, al mismo tiempo, mejorar mis habilidades de MySQL. –

Respuesta

18

Si vez Plan en la búsqueda de attribtes específicas, que es una mala idea serialícelos en una sola columna, ya que tendrá que usar funciones por fila para obtener la información; esto nunca se adapta bien.

Optaría por su segunda opción. Tenga una lista de atributos en una tabla de atributos, los objetos en su propia tabla y una tabla de relaciones de 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) 
    primary key (object_id,attr_id) 

su preocupación por el rendimiento se nota, pero, en mi experiencia, siempre es más costoso para dividir una columna de combinar varias columnas. Si resulta que hay problemas de rendimiento, es perfectamente aceptable romper 3NF por motivos de rendimiento.

En ese caso, lo almacenaría de la misma manera, pero también tendría una columna con los datos en serie sin procesar. Siempre que utilice desencadenantes de inserción/actualización para mantener sincronizados los datos de columna y combinados, no tendrá ningún problema. Pero no debes preocuparte hasta que surja un problema real.

Al usar esos desencadenadores, minimiza el trabajo requerido solo cuando los datos cambian. Al tratar de extraer información de subcolumna, hace trabajo innecesario en cada selección.

+0

Exactamente mi preocupación con la primera estrategia. –

+0

la pregunta es cuál es mejor para el rendimiento que su método es eav cuál es su opinión sobre el modelado de json que almacena datos –

+0

@babakfaghihian, creo que lo cubro en mis últimos dos párrafos, ¿sí? Está bien romper 3NF por rendimiento siempre que comprenda y mitigue los riesgos (de elementos de datos que "no estén de acuerdo" entre sí). Almacenar los datos originales (XML, JSON o lo que sea) es un enfoque para esto. – paxdiablo

1

suena como que necesita algo lamer couchdb, no es un RDBMS.

+0

Eso suena como una solución ideal. Desafortunadamente, me ocupo principalmente de escenarios en los que no tengo la posibilidad de utilizar mucho más que MySQL, y mucho menos de instalar otro DB en el servidor. –

6

Una variación en su solución 2d está a sólo dos mesas (suponiendo que todos los atributos son de un solo tipo):

T1: | columnas de datos de objetos | OBJECT_ID |

T2: | Id. De objeto | nombre_atributo | valor de atributo | (índice único en las primeras 2 columnas)

Esto es aún más eficiente cuando se combina con la tercera solución, p. todos los campos comunes van a T1.

Sstuffing> 1 atributo en la misma burbuja hay recomienda - no se puede filtrar por atributos, no se puede actualizar de manera eficiente

+0

En realidad, eso es exactamente lo que me vino a la mente después de leer nuevamente mis tres estrategias. Suena como la mejor manera de ir. –

+1

Hola. Esto se llama una tabla Entity-Atribute-Value, y es un mal diseño http://programmers.stackexchange.com/questions/93124/eav-is-it-really-bad-in-all-scenarios –

+0

@GabriBotha - las respuestas a la pregunta vinculada de ninguna manera apoyan su aseveración plana y no impugnada de que es un diseño "malo". Es un diseño con defectos específicos, como TODOS los diseños, y situaciones específicas en las que es el mejor enfoque. – DVK

1

si va a editar/manipular/eliminar los atributos en un punto posterior, haciendo una verdadera n: m (segunda opción) será la que yo elija. (O intente convertirlo en 2 tablas donde se repite el mismo atributo. Pero el tamaño de datos será alto)

Si no está tratando con atributos (simplemente capturando y mostrando los datos), puede continuar y almacenar en un campo con algún separador (asegúrese de que el separador no ocurra en el valor del atributo)

1

Si está utilizando un db relacional, entonces 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 deserializar), 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 estilo de clave/valor db en lugar de un DB relacional.

EDITAR - leyendo más de sus comentarios, ¿POR QUÉ está cambiando a un DB si la velocidad es su principal preocupación. ¿Qué es MALO sobre tu implementación XML actual?

2

he usado para implementar this scheme:

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 sostiene GUID s

Si desea seleccionar todas las propiedades de un objeto, se emite:

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 mantener cosas que normalmente no busca (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. Solo contienen valores para las instancias de una cierta clase o sus descendientes. Esto es para evitar uniones adicionales.

No tiene que usar tablas rápidas y limitar todos sus datos a estas cuatro tablas.

+1

Guau, eso es incluso un paso más. Pero, ¿no conduciría eso a una gran cantidad de tablas si tiene una para cada tipo de clase? Y su última declaración SQL realmente me hace esperar que el libro de MySQL que ordené llegue más pronto que tarde .. –

+1

'@ Jörg': esto estaba en' Oracle' y esta es la sintaxis de 'Oracle'. En 'MySQL', deberá implementar esta función de otra forma: http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/ – Quassnoi

+0

Debe crear tablas solo para" propiedades rápidas ": cuando necesita crear un índice compuesto en dos o más propiedades. De lo contrario, solo puede tener '4' tablas básicas. – Quassnoi

3

Permítanme dar un poco de concreción a lo que DVK estaba diciendo.

valores Suponiendo que son del mismo tipo de la mesa se vería así (buena suerte, siento que 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' | 

lo tanto ,
entidad 1 = {('Hacer', 'Ford'), ('Modelo', 'Borde'), ('Color', 'Azul')}
y,
entidad 2 = {('Hacer ',' Chevrolet '), (' Modelo ',' Malibu '), (' MaxSpeed ​​',' 110mph ')}.

+0

¿Qué sucede si quiere decir que una máquina tiene color negro y amarillo? –

Cuestiones relacionadas