Algo así como una herencia en el diseño de base de datos

Suponga que la configuración de una base de datos para almacenar la prueba de choque de datos de varios vehículos. Desea almacenar los datos de las pruebas de choque de lanchas, coches y karts.

Se pueden crear tres tablas separadas: SpeedboatTests, CarTests, y GokartTests. Pero muchas de sus columnas van a ser los mismos en cada tabla (por ejemplo, el id de empleado de la persona que realizó la prueba, la dirección de la colisión (frontal, lateral, trasera), etc.). Sin embargo, un montón de columnas será diferente, por lo que no quiero poner todos los datos de prueba en una sola tabla, porque vas a tener muy pocas columnas que siempre va a ser null para lanchas, unos cuantos que siempre será nulo para los coches, y muy pocos que siempre va a ser null para go-karts.

Digamos que usted también desea almacenar cierta información que no está directamente relacionado con las pruebas (tales como el identificador de empleado del diseñador de la cosa que está siendo probado). Estas columnas no parecen adecuadas para poner en «Pruebas» de la tabla en absoluto, sobre todo porque van a ser repetido para todas las pruebas en el mismo vehículo.

Permítanme ilustrar una posible disposición de las mesas, así que usted puede ver las cuestiones involucradas.

Lanchas rápidas 
id | col_about_speedboats_but_not_tests1 | col_about_speedboats_but_not_tests2 

Coches 
id | col_about_cars_but_not_tests1 | col_about_cars_but_not_tests2 

Gokarts 
id | col_about_gokarts_but_not_tests1 | col_about_gokarts_but_not_tests2 

Pruebas 
id | tipo de | id_in_type | col_about_all_tests1 | col_about_all_tests2 
(id_in_type se refieren a la columna de id de uno de los siguientes tres tablas, 
dependiendo del valor del tipo) 

SpeedboatTests 
id | speedboat_id | col_about_speedboat_tests1 | col_about_speedboat_tests2 

CarTests 
id | car_id | col_about_car_tests1 | col_about_car_tests2 

GokartTests 
id | gokart_id | col_about_gokart_tests1 | col_about_gokart_tests2 

Lo que es bueno/malo de esta estructura y cuál sería la mejor manera de implementar algo como esto?

Lo que si también hay algo de información que se aplica a todos los vehículos que se desea tener en una tabla de Vehículos? Sería el CarTests tabla, a continuación, busque algo como…

id | vehicle_id | ... 

Con una tabla de Vehículos como este: 
id | tipo de | id_in_type 
(con id_in_type que apunta a la identificación de una lancha rápida, el coche, o go-kart) 

Esto es sólo llegar a ser un real desastre que parece. ¿Cómo DEBE algo como esto ser configurado?

6 Kommentare

  1. 39

    La type y id_in_type el diseño se llama Polimórficos Asociaciones. Este diseño rompe las reglas de normalización de múltiples maneras. Si nada más, debería ser una bandera roja que no puede declarar una verdadera restricción de clave externa, porque el id_in_type puede hacer referencia a cualquiera de varias tablas.

    Aquí es una forma mejor de definir las tablas:

    • Hacer un resumen de la tabla de Vehicles para proporcionar un resumen de punto de referencia para todos los vehículos sub-tipos y pruebas de vehículos.
    • Cada vehículo sub-tipo tiene una clave primaria que no de incremento automático, pero en lugar de referencias Vehicles.
    • Cada prueba sub-tipo tiene una clave primaria que no de incremento automático, pero en lugar de referencias Tests.
    • Cada prueba sub-tipo también tiene una clave externa para el correspondiente vehículo sub-tipo.

    Aquí la muestra de DDL:

    CREATE TABLE Vehicles (
     vehicle_id INT AUTO_INCREMENT PRIMARY KEY
    );
    
    CREATE TABLE Speedboats (
     vehicle_id INT PRIMARY KEY,
     col_about_speedboats_but_not_tests1 INT,
     col_about_speedboats_but_not_tests2 INT,
     FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
    );
    
    CREATE TABLE Cars (
     vehicle_id INT PRIMARY KEY,
     col_about_cars_but_not_tests1 INT,
     col_about_cars_but_not_tests2 INT,
     FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
    );
    
    CREATE TABLE Gokarts (
     vehicle_id INT PRIMARY KEY,
     col_about_gokarts_but_not_tests1 INT,
     col_about_gokarts_but_not_tests2 INT,
     FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
    );
    
    CREATE TABLE Tests (
     test_id INT AUTO_INCREMENT PRIMARY KEY,
     col_about_all_tests1 INT,
     col_about_all_tests2 INT
    );
    
    CREATE TABLE SpeedboatTests (
     test_id INT PRIMARY KEY,
     vehicle_id INT NOT NULL,
     col_about_speedboat_tests1 INT,
     col_about_speedboat_tests2 INT,
     FOREIGN KEY(test_id) REFERENCES Tests(test_id),
     FOREIGN KEY(vehicle_id) REFERENCES Speedboats(vehicle_id)
    );
    
    CREATE TABLE CarTests (
     test_id INT PRIMARY KEY,
     vehicle_id INT NOT NULL,
     col_about_car_tests1 INT,
     col_about_car_tests2 INT,
     FOREIGN KEY(test_id) REFERENCES Tests(test_id),
     FOREIGN KEY(vehicle_id) REFERENCES Cars(vehicle_id)
    );
    
    CREATE TABLE GokartTests (
     test_id INT PRIMARY KEY,
     vehicle_id INT NOT NULL,
     col_about_gokart_tests1 INT,
     col_about_gokart_tests2 INT,
     FOREIGN KEY(test_id) REFERENCES Tests(test_id),
     FOREIGN KEY(vehicle_id) REFERENCES Gokarts(vehicle_id)
    );
    

    También declarar Tests.vehicle_id que las referencias Vehicles.vehicle_id y deshacerse de la vehicle_id claves foráneas en cada prueba sub-tipo de la tabla, pero que permitiría a las anomalías, tales como una lancha rápida de la prueba que hace referencia a un gokart de la id.

    • Esto fue muy útil y completo. Gracias!
    • todas las demás respuestas, salvo ésta, y, tal vez, la mención de Martin Fowler, deben ser retirados o enterrados en el olvido… OMG..
    • Gracias @Rafa! Saludos
    • Esta es la Tabla de Clase de enfoque de Herencia. Otras alternativas son numeradas aquí: stackoverflow.com/a/3579462/200987
    • Hay un problema con esto: Usted puede tener un coche y una gocart con el mismo vehicle_id. Sin embargo, esto es una irresoluble inconveniente del modelo relacional. Hay un método alternativo (Como el usado por Laravel y Ruby): inversa de la relación, el uso de ambos «vehicle_id» y «vehicle_type». Usted obtener singularidad, pero el sacrificio de la FK de restricciones debido a vehicle_id ahora los puntos en varias mesas, en otras palabras, usted podría tener el subtipo menos tipos de base, pero que no tenga varios subtipos de cada tipo. Que la solución es correcta depende de la «función de seguridad» que usted prefiera.
    • Cada base de datos con experiencia desarrollador sé que evita el uso de claves foráneas de todos modos.
    • Podrías explicar a qué te refieres? Sin FKs, ¿cómo garantizar la integridad de los datos? No todos los tipos de restricción que es posible en el modelo relacional (más notablemente, el polimorfismo), por lo que hay que tener compromisos. Pero en mi experiencia, nada que no se aplica en el nivel de DB, con el tiempo serán contaminados con datos no válidos — backend código es generalmente de muy dinámica.
    • Ver este comentario de un ingeniero senior en github. Muchos Administradores de bases de datos MySQL de acuerdo con sus razones. Por otro lado, tienes razón de que la eliminación de FK restricciones crea un riesgo para su aplicación. Usted tiene que asegurarse de que el código de la aplicación está diseñada para «hacer lo correcto». Pero también los datos de ejecución de trabajos de limpieza para los inevitables errores.
    • Diría usted que ha cambiado el punto de vista que se expresa en SQL Antipatrones 7.4: «…el uso de restricciones como claves externas para asegurar la integridad referencial. Polimórficos Asociaciones a menudo se basa demasiado en el código de la aplicación en lugar de meta-datos». Estoy tratando con un polimórficos relación que necesita comprobaciones de integridad, y se preguntaba si debería encapsular los controles en el código, o el uso de SQL update/insert/delete disparadores para emular una más «completo» referencial sistema de control.
    • Sí, he cambiado mi opinión sobre eso. Es cierto que sin FK restricciones, usted tiene un riesgo de la integridad de los datos de descomponerse. Idealmente, no tendríamos ni compromiso. Pero en escenarios del mundo real, a las empresas una mayor prioridad en la maximización del rendimiento de las consultas. Muchas veces me he dado presentaciones en el modelado de datos, y la única pregunta es, «sí, pero ¿¿que realizar?» La línea de fondo es que el rendimiento es más importante para la mayoría de la gente. Estoy un poco triste decir esto, pero tengo que reconocer que es.
    • En mi opinión, sería mejor utilizar una caja fuerte, normalizado y «un poco lento» principal base de datos para escribir la «verdad absoluta» y, a continuación, denormalize de datos en la que almacena en caché (elástico, redis, bigquery, etc) cuando el rendimiento es importante. Comprometer la única fuente de verdad para que el rendimiento no es algo que yo estaría dispuesto a hacer.
    • Buena suerte con eso. 🙂

  2. 14

    Para la asignación de las jerarquías de herencia de tablas de base de datos, creo que Martin Fowler establece las alternativas bastante bien en su libro de los Patrones de la Arquitectura de Aplicaciones Empresariales.

    http://martinfowler.com/eaaCatalog/singleTableInheritance.html

    http://martinfowler.com/eaaCatalog/classTableInheritance.html

    http://martinfowler.com/eaaCatalog/concreteTableInheritance.html

    Si el número de campos/columnas es pequeño para las subclases, luego de una sola mesa herencia suele ser el más sencillo de tratar.

    Si usted está usando PostgreSQL para su base de datos y que esté dispuesto a ate a una base de datos específica de la función, es compatible con la herencia de tablas directamente:

    http://www.postgresql.org/docs/8.3/static/ddl-inherit.html

    • Yo añadiría que, con referencia específica a la real lío que se alude en la pregunta original que los extranjeros clave desde el punto específico del tipo de vehículo para el resumen vehículo de la tabla. es decir lancha rápida (vehicle_id FK, speedboat_specific_column1, etc…)
  3. 0

    Me gustaría que se rompen en las diferentes tablas, por ejemplo, Vehículo (ID, tipo, etc) VehicleAttributes ()VehicleID, AttributeID, Valor), CrashTestInfo(VehicleID, CrashtestID, Fecha, etc.) CrashtestAttributes(CrashTestID, AttributeID, Valor)

    O en lugar de atributos, tablas separadas para cada conjunto de detalles similares que deben ser registradas.

    • Que la Entidad-Atributo-Valor, que es un exceso para el OP del escenario.
  4. 0

    Si usted está usando SQLAlchemy, un asignador de objeto-relacional para Python, puede configurar la manera en que las jerarquías de herencia se asignan a las tablas de base de datos. Objeto-relacionales mapeados son buenas para domesticar lo contrario tedioso SQL.

    Tu problema podría ser un buen ajuste para la vertical de las tablas. En lugar de almacenar todo en el esquema, almacenar el tipo de objeto y la clave principal de una tabla y la clave/valor de tuplas de cada objeto en otra tabla. Si realmente fueron guardar coche de pruebas, esta configuración sería mucho más fácil añadir nuevos tipos de resultados.

  5. -1

    Hacer una búsqueda en google de «gen-spec relacional de modelado». Usted encontrará artículos sobre cómo configurar las tablas que almacenan los atributos de la generalización de la entidad (lo que OO programadores podría llamar la superclase), tablas separadas para cada una de las entidades especializadas (subclases), y cómo el uso de claves foráneas para vincular todos juntos.

    Los mejores artículos, la OMI, discutir gen-spec en términos de RE modelado. Si usted sabe cómo traducir un modelo ER en un modelo relacional, y de allí a las tablas SQL, usted sabrá qué hacer una vez que te muestran cómo el modelo gen-spec en ER.

    Si usted acaba de google en «gen-spec», la mayoría de lo que vas a ver es orientado a objetos, no relacional orientado. Que cosas pueden ser de utilidad, siempre y cuando usted sabe cómo superar el objeto relacional desajuste de impedancia.

    • Sería grande si usted podría proporcionar algunos enlaces directos.
    • Esto es sólo la Tabla de Clase de Enfoque (como se hace referencia en la respuesta, y el que hace referencia a Fowler)
  6. -3

    Su diseño es razonable, y está siguiendo el correcto reglas de normalización. Usted puede ser que falte un Vehículo de la tabla con un Id de Vehículo y el Tipo (es decir, el «padre» para Lanchas, Coches, y Gokarts… donde te gustaría seguir cosas como «DesignedByUserId»). Entre el Vehículo de la tabla y las Lanchas rápidas de la tabla es un uno – a – uno, y entre el Vehículo y la Lancha de motor/Coches/GoKarts hay un 1-y-sólo-1 relación (es decir. un vehículo sólo puede tener 1 registro para lancha de motor, coches o go karts…) aunque la mayoría de los db no ofrecen un fácil mecanismo de ejecución de este.

    Una normalización de la regla que ayuda a identificar este tipo de cosas es que un campo debe dependen únicamente de la clave principal de la tabla. En un cuadro consolidado donde lancha de motor, coches, y gokart los resultados de la prueba se almacenan juntos, a continuación, los coches campos relacionados no sólo dependen de la fecha de la prueba, sino también en el vechicle de identificación y tipo de vehículo. La clave principal para la prueba tabla de resultados es la fecha de la prueba + de identificación del vehículo y el tipo de vehículo no es lo que hace que la prueba de la fila de datos única (es decir. existe de todos modos para llevar a cabo una prueba en 01/01/200912:30 de la tarde en un vehículo específico, que es tanto una lancha a motor y coche… no… no puede ser hecho).

    No estoy explicando la normalización de la regla especialmente bien… pero 3ª/4ª/5ª formas normales reglas siempre me confunde cuando me lea las descripciones formales. Uno de esos (3ª/4ª/5ª) se ocupa de los campos dependiendo de la clave principal y sólo la clave principal. La regla de hacer la suposición de que la clave principal ha sido correctamente identificado (incorrectamente defininh la clave principal es demasiado fácil de hacer).

    • -1 porque Polimórficos de Asociaciones de diseño (la type y id_in_type cosa) es no un diseño normalizado.
    • Uhmm… ver en.wikipedia.org/wiki/Fourth_normal_form. La pizza ejemplo es bastante razonable.
    • Estás diciendo {test_id, tipo} -> -> {id_in_type} pasa 4NF, por lo tanto {test_id, tipo} es un súper tecla? Estoy hablando acerca de la definición básica de una relación, en la que cada atributo representa el valor de una «cosa», pero id_in_type es de tres tipos diferentes de cosas.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea