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.
@Corazón de piedra
Iría aquí con EAV y MVC hasta el final.
@Bill Karvin
Todas esas cosas que has mencionado aquí:
en mi opinión, no pertenezco 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 el lenguaje de programación de una aplicación.
En mi opinión, usar una base de datos de esta manera es como usar una roca para clavar un clavo. Puedes hacerlo con una roca, pero ¿no se supone que debes usar un martillo que sea más preciso y específicamente diseñado para este tipo de actividad?
Este problema se puede resolver 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 del producto, puede procesarlos en lotes si necesita datos de cada fila de esta tabla.
Ir 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 para ellas tablas de índice que almacenarían los datos requeridos 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 cada vez 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 preprocesar los datos y luego simplemente procesar los datos optimizados en su aplicación principal.
fuente
you can always use Erlang, C++, Go Language to pre-process the data
¿Qué querías decir? En lugar de DB, use Go lang? ¿Podría por favor explicar eso?Si uso el
Class Table Inheritance
significado:Lo que me gusta más 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 debo tener en marcha cuando un atributo que solo es común a 1 tipo, luego se vuelve común a 2, luego a 3, etc.?
Por ejemplo: (este 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 televisor podría ser el único que tenemos que tiene un consumo de energía. Entonces pondría el
power_consumption
atributo en eltv_type_table
. Pero luego comenzamos a llevar sistemas de cine en casa que también tienen unapower_consumption
propiedad. OK, es solo otro producto, así que también agregaré este campostereo_type_table
, ya que probablemente sea más fácil en este momento. Pero con el tiempo a medida que comenzamos a transportar cada vez más productos electrónicos, nos damos cuenta de quepower_consumption
es lo suficientemente amplio como para que esté en elmain_product_table
. ¿Qué debería hacer ahora?Agregue el campo a la
main_product_table
. Escriba un script para recorrer la electrónica y coloque el valor correcto de cada unotype_table
enmain_product_table
. Luego suelte esa columna de cada unotype_table
.Ahora si siempre estaba usando la misma
GetProductData
clase 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 ser refactorizado, debería ser solo para esa Clase.fuente
Puede tener una tabla de productos y una tabla separada de ProductAdditionInfo con 3 columnas: ID de producto, nombre de información adicional, valor de información adicional. Si el color es utilizado por muchos pero no todos los tipos de Productos, podría ser una columna anulable 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.
fuente
3 columns: product ID, additional info name, additional info value
que entendía el concepto. Y en realidad he hecho esto antes, y me encontré con problemas. Sin embargo, no recuerdo por el momento cuáles fueron esos problemas.