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 muchas columnas, la mayoría de las cuales son NULL en cualquier fila dada.
Herencia de tabla de clase : una tabla para productos, que almacena atributos comunes a todos los tipos de productos. Luego, una tabla por tipo de producto, que almacena atributos específicos para ese tipo de producto.
Herencia de tablas de concreto : no hay tabla para los atributos comunes de los productos. 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, que almacena 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 usar patrones de diseño elegantes para describir esto, como Fachada y Memento. Pero independientemente de que tenga un conjunto de atributos que no se pueden consultar fácilmente en SQL; tienes que recuperar todo el blob de vuelta a la aplicación y ordenarlo por ahí.
Entity-Attribute-Value : una tabla para productos y una tabla que pivota los atributos en 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. Vea otras preguntas con la etiqueta eav en StackOverflow para algunos de los escollos.
He escrito más sobre esto en una presentación, Modelado de datos extensibles .
Pensamientos adicionales sobre EAV: aunque muchas personas parecen estar a favor de 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 que una columna sea obligatoria (equivalente a
NOT NULL
).
- No hay forma de usar tipos de datos SQL para validar entradas.
- No hay forma de garantizar que los nombres de los atributos se deletreen de manera consistente.
- No hay forma de poner una clave externa en los valores de cualquier atributo dado, por ejemplo, para una tabla de búsqueda.
- Obtener resultados en un diseño tabular convencional es complejo y costoso, porque para obtener atributos de varias filas debe hacer
JOIN
para cada atributo.
El grado de flexibilidad que EAV le brinda requiere sacrificios en otras áreas, probablemente haciendo que su código sea tan complejo (o peor) de lo que hubiera sido resolver el problema original de una manera más convencional.
Y en la mayoría de los casos, no es necesario 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 se aplica una estructura consistente al menos para las entradas del mismo tipo de producto.
Usaría EAV solo si se debe permitir que cada fila tenga potencialmente un conjunto distinto de atributos. Cuando tienes un conjunto finito de tipos de productos, EAV es excesivo. La herencia de la tabla de clase sería mi primera opción.
Actualización 2019: cuanto más veo a las personas que usan JSON como una solución para el problema de "muchos atributos personalizados", menos me gusta esa solución. Hace que las consultas sean demasiado complejas, incluso cuando se utilizan funciones especiales de JSON para admitirlas. Se necesita mucho más espacio de almacenamiento para almacenar documentos JSON, en comparación con el almacenamiento en filas y columnas normales.
Básicamente, ninguna de estas soluciones es fácil o eficiente en una base de datos relacional. Toda la idea de tener "atributos variables" está fundamentalmente en desacuerdo con la teoría relacional.
Todo se reduce a que tiene que elegir una de las soluciones en función de cuál es la menos mala para su aplicación. Por lo tanto, necesita saber cómo va a consultar los datos antes de elegir un diseño de base de datos. No hay forma de elegir una solución que sea "mejor" porque cualquiera de las soluciones podría ser la mejor para una aplicación determinada.