Cómo diseñar una tabla de productos para muchos tipos de productos donde cada producto tiene muchos parámetros

No tengo mucha experiencia en diseño de mesas. Mi objective es crear una o más tablas de productos que cumplan con los requisitos a continuación:

  • Soporta muchos tipos de productos (TV, Teléfono, PC, …). Cada tipo de producto tiene un conjunto diferente de parámetros, como:

    • El teléfono tendrá color, tamaño, peso, sistema operativo …

    • La PC tendrá CPU, HDD, RAM …

  • El conjunto de parámetros debe ser dynamic. Puede agregar o editar cualquier parámetro que desee.

¿Cómo puedo cumplir estos requisitos sin una tabla separada para cada tipo de producto?

Tiene al menos estas cinco opciones para modelar la jerarquía de tipos que describe:

  • Herencia de tabla única : una tabla para todos los tipos de productos, con suficientes columnas para almacenar todos los atributos de todos los tipos. Esto significa una gran cantidad de columnas, la mayoría de las cuales son NULL en cualquier fila determinada.

  • Herencia de Tabla de Clase : una tabla para Productos, almacenando atributos comunes a todos los tipos de productos. Luego, una tabla por tipo de producto, almacenando atributos específicos para ese tipo de producto.

  • Herencia de Mesa de Concreto : no hay tabla para atributos de Productos comunes. En cambio, una tabla por tipo de producto, que almacena los atributos comunes del producto y los atributos específicos del producto.

  • LOB serializado : una tabla para productos, almacenando atributos comunes a todos los tipos de productos. Una columna adicional almacena un BLOB de datos semiestructurados, en XML, YAML, JSON u otro formato. Este BLOB le permite almacenar los atributos específicos de cada tipo de producto. Puede utilizar patrones de diseño elegantes para describir esto, como Fachada y Memento. Pero independientemente de que tenga una burbuja de atributos que no se pueden consultar fácilmente en SQL; tienes que recuperar todo el blob de vuelta a la aplicación y solucionarlo allí.

  • Entity-Attribute-Value : una tabla para Productos, y una tabla que pivota atributos a filas, en lugar de columnas. EAV no es un diseño válido con respecto al paradigma relacional, pero muchas personas lo usan de todos modos. Este es el “Patrón de Propiedades” mencionado por otra respuesta. Consulte otras preguntas con la etiqueta eav en StackOverflow para conocer algunas de las trampas.

He escrito más sobre esto en una presentación, Modelado de datos extensible .


Pensamientos adicionales sobre EAV: Aunque muchas personas parecen preferir el EAV, yo no. Parece la solución más flexible y, por lo tanto, la mejor. Sin embargo, tenga en cuenta el adagio TANSTAAFL . Estas son algunas de las desventajas de EAV:

  • No hay forma de hacer obligatoria una columna (equivalente a NOT NULL ).
  • No hay forma de usar los tipos de datos SQL para validar las entradas.
  • No hay forma de garantizar que los nombres de atributos se deletreen de forma coherente.
  • No hay forma de poner una clave externa en los valores de ningún atributo dado, por ejemplo, para una tabla de búsqueda.
  • La obtención de resultados en un diseño tabular convencional es compleja y costosa, ya que para obtener atributos de múltiples filas, debe realizar JOIN para cada atributo.

El grado de flexibilidad que le otorga EAV requiere sacrificios en otras áreas, probablemente haciendo que su código sea tan complejo (o peor) de lo que hubiera sido para resolver el problema original de una manera más convencional.

Y en la mayoría de los casos, es innecesario tener ese grado de flexibilidad. En la pregunta del OP sobre los tipos de productos, es mucho más simple crear una tabla por tipo de producto para los atributos específicos del producto, por lo que tiene una estructura consistente forzada al menos para las entradas del mismo tipo de producto.

Yo usaría EAV solo si se debe permitir que cada fila tenga un conjunto distinto de atributos. Cuando tiene un conjunto finito de tipos de producto, EAV es excesivo. La herencia de la tabla de clases sería mi primera opción.

@Corazón de piedra

Me gustaría ir aquí con EAV y MVC todo el camino.

@Bill Karvin

Estas son algunas de las desventajas de EAV:

 No way to make a column mandatory (equivalent of NOT NULL). No way to use SQL data types to validate entries. No way to ensure that attribute names are spelled consistently. No way to put a foreign key on the values of any given attribute, eg 

para una tabla de búsqueda.

Todas esas cosas que has mencionado aquí:

  • validación de datos
  • nombres de atributo ortografía validación
  • columnas / campos obligatorios
  • manejo de la destrucción de atributos dependientes

en mi opinión, no pertenecen en absoluto a una base de datos porque ninguna de las bases de datos es capaz de manejar esas interacciones y requisitos en un nivel adecuado como lo hace un lenguaje de progtwigción de una aplicación.

En mi opinión, usar una base de datos de esta manera es como usar una piedra para clavar un clavo. Puedes hacerlo con una roca, pero ¿no deberías usar un martillo que sea más preciso y esté específicamente diseñado para este tipo de actividad?

La obtención de resultados en un diseño tabular convencional es compleja y costosa, ya que para obtener atributos de múltiples filas, debe realizar JOIN para cada atributo.

Este problema puede resolverse haciendo pocas consultas sobre datos parciales y procesándolos en un diseño tabular con su aplicación. Incluso si tiene 600 GB de datos de productos, puede procesarlos en lotes si necesita datos de cada fila de esta tabla.

Más allá Si desea mejorar el rendimiento de las consultas, puede seleccionar ciertas operaciones como, por ejemplo, informes o búsqueda de texto global y preparar las tablas de índice que almacenarían los datos necesarios y se regenerarían periódicamente, digamos cada 30 minutos.

Ni siquiera necesita preocuparse por el costo del almacenamiento adicional de datos porque se vuelve más barato y más barato cada día.

Si todavía le preocupa el rendimiento de las operaciones realizadas por la aplicación, siempre puede usar Erlang, C ++, Go Language para procesar previamente los datos y luego simplemente procesar los datos optimizados en su aplicación principal.

Si uso Class Table Inheritance significa:

una tabla para Productos, almacenando atributos comunes a todos los tipos de productos. Luego, una tabla por tipo de producto, almacenando atributos específicos para ese tipo de producto. -Bill Karwin

Lo que me gusta es lo mejor de las sugerencias de Bill Karwin. Puedo prever un inconveniente, que trataré de explicar cómo evitar que se convierta en un problema.

¿Qué plan de contingencia debería tener cuando un atributo que solo es común para 1 tipo, luego se vuelve común para 2, luego 3, etc.?

Por ejemplo: (esto es solo un ejemplo, no es mi problema real)

Si vendemos muebles, podríamos vender sillas, lámparas, sofás, televisores, etc. El tipo de TV podría ser el único tipo que tenemos que tiene un consumo de energía. Entonces pondría el atributo power_consumption en la tv_type_table . Pero luego comenzamos a llevar sistemas de cine en casa que también tienen una propiedad de power_consumption . OK es solo otro producto, así que stereo_type_table este campo al stereo_type_table también, ya que probablemente sea el más fácil en este momento. Pero con el tiempo, a medida que comenzamos a transportar más y más productos electrónicos, nos damos cuenta de que el power_consumption es lo suficientemente amplio como para que esté en la main_product_table . ¿Qué debería hacer ahora?

Agregue el campo a main_product_table . Escriba un guión para recorrer los componentes electrónicos y coloque el valor correcto de cada type_table en la main_product_table . A continuación, suelte esa columna de cada type_table .

Ahora si siempre estuve usando la misma clase GetProductData para interactuar con la base de datos para extraer la información del producto; entonces, si algún cambio en el código ahora necesita una refactorización, deberían ser solo para esa Clase.

Puede tener una tabla Producto y una tabla ProductAdditionInfo separada con 3 columnas: ID de producto, nombre de información adicional, valor de información adicional. Si el color lo utilizan muchos, pero no todos los tipos de Productos, podría ser una columna que se pueda anular en la tabla Producto, o simplemente ponerlo en ProductAdditionalInfo.

Este enfoque no es una técnica tradicional para una base de datos relacional, pero he visto que se usa mucho en la práctica. Puede ser flexible y tener un buen rendimiento.

Steve Yegge llama a esto el patrón Propiedades y escribió una larga publicación sobre su uso.