Este es un diseño OO clásico para la falta de coincidencia de impedancia de tablas relacionales. El diseño de la tabla que ha descrito se conoce como 'tabla por subclase'. Los tres diseños más comunes son compromisos en comparación con el aspecto real de sus objetos en su aplicación:
- Tabla por clase concreta
- Tabla por jerarquía
- Tabla por subclase
El diseño que no le gusta, "donde las tablas tienen 100 columnas y la mayoría de los valores son NULOS", es 2. una tabla para almacenar toda la jerarquía de especialización. Este es el menos flexible por todo tipo de razones, incluido:si su aplicación requiere una nueva subclase, debe agregar columnas. El diseño que describe se adapta mucho mejor al cambio porque puede agregarlo y extenderlo agregando una nueva tabla de subclase descrita por un valor en product_type.
La opción restante, 1. Tabla por clase concreta, generalmente no es deseable debido a la duplicación que implica implementar todos los campos comunes en cada tabla de especialización. Aunque, las ventajas son que no necesitará realizar uniones y las tablas de subclase pueden incluso estar en diferentes instancias de base de datos en un sistema muy grande.
El diseño que describiste es perfectamente viable. La variación a continuación es cómo se vería si estuviera usando una herramienta ORM para realizar sus operaciones CRUD. Observe cómo el ID en cada tabla de subclase ES el valor FK de la tabla principal en la jerarquía. Un buen ORM administrará automáticamente la tabla CRUD de subclase correcta en función del valor de los valores discriminadores en product.id y product.product_type_id solo. Ya sea que esté planeando usar un ORM o no, mire la documentación de la subclase unida de hibernate, aunque solo sea para ver las decisiones de diseño que tomaron.
product
=======
id INT
product_name VARCHAR
product_type_id INT -> Foreign key to product_type.product_type_id
valid_since DATETIME
valid_to DATETIME
magazine
========
id INT -> Foreign key to product.product_id
title VARCHAR
..
web_site
========
id INT -> Foreign key to product.product_id INT
name VARCHAR
..