Estoy trabajando para actualizar la base de datos de productos de nuestro sitio web. Está construido en MySQL, pero esta es más una pregunta de patrón de diseño de base de datos general.
Estoy planeando cambiar a un patrón de Supertipo / Subtipo. Nuestra base de datos actual / anterior es principalmente una tabla única que tiene datos sobre un solo tipo de producto. Estamos buscando expandir nuestra oferta de productos para incluir productos diferentes.
Este nuevo diseño borrador es así:
Product product_[type] product_attribute_[name]
---------------- ---------------- ----------------------------
part_number (PK) part_number (FK) attributeId (PK)
UPC specific_attr1 (FK) attribute_name
price specific_attr2 (FK)
... ...
Tengo una pregunta sobre las tablas de atributos del producto. La idea aquí es que un producto puede tener una lista de atributos dados, como color: rojo, verde, azul o material: plástico, madera, cromo, aluminio, etc.
Esta lista se almacenaría en una tabla y la clave primaria (PK) para ese elemento de atributo se utilizará en la tabla de productos específica como una clave externa (FK).
(El libro de Martin Fowler, Patterns of Enterprise Application Architecture, llama a esto " Mapeo de claves externas ")
Esto permite que la interfaz de un sitio web extraiga la lista de atributos para un tipo de atributo dado y lo escupe en un menú de selección desplegable o en algún otro elemento de la interfaz de usuario. Esta lista puede considerarse una lista "autorizada" de valores de atributos.
El número de uniones que termina sucediendo cuando se tira de un producto específico me parece excesivo. Debe unir todas las tablas de atributos del producto al producto para poder obtener los campos de ese atributo. Comúnmente, ese campo podría ser simplemente una cadena (varchar) para su nombre.
Este patrón de diseño termina creando una gran cantidad de tablas, así como también termina con una tabla para cada atributo. Una idea para contrarrestar esto sería crear algo más de una tabla de "bolsa de agarre" para todos los atributos del producto. Algo como esto:
product_attribute
----------------
attributeId (PK)
name
field_name
De esta manera, su tabla podría verse así:
1 red color
2 blue color
3 chrome material
4 plastic material
5 yellow color
6 x-large size
Esto podría ayudar a reducir el deslizamiento de la tabla, pero no reduce el número de uniones y se siente un poco mal combinar tantos tipos diferentes en una sola tabla. Pero podría obtener todos los atributos de "color" disponibles con bastante facilidad.
Sin embargo, puede haber un atributo que tenga más campos que solo "nombre", como el valor RGB de un color. Esto requeriría que ese atributo específico posiblemente tenga otra tabla o que tenga un solo campo para el nombre: par de valores (que tiene sus propios inconvenientes).
El último patrón de diseño que se me ocurre es almacenar el valor de atributo real en la tabla de productos específica y no tener una "tabla de atributos" en absoluto. Algo como esto:
Product product_[type]
---------------- ----------------
part_number (PK) part_number (FK)
UPC specific_attr1
price specific_attr2
... ...
En lugar de una clave externa para otra tabla, contendría el valor real como:
part_number color material
----------- ----- --------
1234 red plastic
Esto eliminaría las uniones y evitaría el deslizamiento de la tabla (¿tal vez?). Sin embargo, esto evita tener una "lista autorizada" de atributos. Puede devolver todos los valores ingresados actualmente para un campo determinado (es decir, color), pero esto también elimina la idea de tener una "lista autorizada" de valores para un atributo dado.
Para tener esa lista, aún tendría que crear una tabla de atributos de “bolsa de agarre” o tener varias tablas (arrastre de tabla) para cada atributo.
Esto crea el mayor inconveniente (y por qué nunca he usado este enfoque) de tener ahora el nombre del producto en varias ubicaciones.
Si tiene el valor de color de "rojo" en la "tabla de atributos maestros" y también lo almacena en la tabla "producto_ [tipo]", una actualización de la tabla "maestra" causará un posible problema de integridad de datos si la aplicación no No actualice todos los registros con el valor anterior en la tabla "product_type" también.
Entonces, después de mi larga explicación y análisis de este escenario, me doy cuenta de que este no puede ser un escenario poco común e incluso podría haber un nombre para este tipo de situación.
¿Existen soluciones generalmente aceptadas para este desafío de diseño? ¿Es aceptable el número potencialmente grande de uniones si las tablas son relativamente pequeñas? ¿Almacenar el nombre del atributo, en lugar de un atributo PK, es aceptable en alguna situación? ¿Hay otra solución en la que no estoy pensando?
Algunas notas sobre esta base de datos / aplicación del producto:
- Los productos no se actualizan / agregan / eliminan con frecuencia
- Los atributos no se actualizan / agregan / eliminan con frecuencia
- La tabla se consulta con mayor frecuencia para leer / devolver información
- El almacenamiento en caché del lado del servidor está habilitado para almacenar en caché el resultado de una consulta / resultado dado
- Planeo comenzar con un solo tipo de producto y extender / agregar otros con el tiempo y tendré potencialmente más de 10 tipos diferentes
fuente
Respuestas:
Yo personalmente usaría un modelo similar al siguiente:
La tabla de productos sería bastante básica, los detalles de su producto principal:
Segundo, la tabla de atributos para almacenar cada uno de los diferentes atributos.
Finalmente, cree la tabla product_attribute como la tabla JOIN entre cada producto y sus atributos asociados.
Dependiendo de cómo desee utilizar los datos, está viendo dos combinaciones:
Ver SQL Fiddle con Demo . Esto devuelve datos en el formato:
Pero si desea devolver los datos en un
PIVOT
formato donde tiene una fila con todos los atributos como columnas, puede usarCASE
declaraciones con un agregado:Ver SQL Fiddle con Demo . Los datos se devuelven en el formato:
Como puede ver, los datos pueden estar en un mejor formato para usted, pero si tiene un número desconocido de atributos, se volverá insostenible fácilmente debido a los nombres de los atributos de codificación rígida, por lo que en MySQL puede usar declaraciones preparadas para crear pivotes dinámicos . Su código sería el siguiente (Ver SQL Fiddle With Demo ):
Esto genera el mismo resultado que la segunda versión sin necesidad de codificar nada. Si bien hay muchas formas de modelar esto, creo que este diseño de base de datos es el más flexible.
fuente
Me gustaría ampliar la respuesta de Taryn y modificar la tabla de atributos para tener fk_attribute_type_id columna que estará en lugar de nombre_atributo columna y puntos de attribute_type nueva mesa.
Por lo tanto, tiene tipos de atributos estructurados en una tabla y puede cambiarlos en cualquier momento en un solo lugar.
En mi opinión, es mejor trabajar con el tipo de "marcado" (tabla con tipos posibles) que con el tipo enum (como está en la columna nombre_atributo (y además de eso, en realidad no es nombre, su tipo de atributo)).
fuente