¿Debo agregar claves foráneas transitivas?

11

Ejemplo simple: hay una mesa de clientes.

create table Customers (
  id integer,
  constraint CustomersPK primary key (id)
)

Todos los demás datos en la base de datos deben vincularse a a Customer, por ejemplo, se Ordersve así:

create table Orders (
  id integer,
  customer integer,
  constraint OrdersPK primary key (customer, id),
  constraint OrdersFKCustomers foreign key (customer) references Customers (id)
)

Supongamos que ahora hay una tabla que vincula a Orders:

create table Items (
  id integer,
  customer integer,
  order integer,
  constraint ItemsPK primary key (customer, id),
  constraint ItemsFKOrders foreign key (customer, order) references Orders (customer, id)
)

¿Debo agregar una clave externa separada de Itemsa Customers?

...
constraint ItemsFKCustomers foreign key (customer) references Customers (id)

Una imagen en su lugar: ¿debo agregar la línea discontinua / FK?

Esquema de ejemplo simple


Editar: he agregado definiciones de clave principal a las tablas. Me gustaría volver a repetir el punto que mencioné anteriormente: la base de datos está básicamente aislada por los clientes, como una medida de corrección / seguridad. Por lo tanto, todas las claves primarias contienen la customerID.

vektor
fuente
2
No, no deberías No hay necesidad de FK extra. La restricción es aplicada por los otros dos FK.
ypercubeᵀᴹ
@ypercube ¿Hay alguna penalización de rendimiento por tener un FK redundante? ¿Alguna ventaja que se te ocurra? ...
vektor
1
@vektor, los aspectos de rendimiento probablemente varían de un rdbms a otro, pero en general, obtienes un impacto en el rendimiento para cada nuevo FK que agregas, porque cada inserción / actualización / eliminación en una de las tablas PK / FK debe verificarse contra el restricción. Con tablas PK grandes, esta penalización de rendimiento puede ser bastante severa.
Daniel Hutmacher

Respuestas:

6

Creo que esta es la idea original.

ingrese la descripción de la imagen aquí

Lo primero que debe notar es que la PK en la tabla LineItem tiene tres atributos {CustomerID, CustomerOrderNo, OdrerItemNo}, en lugar de solo dos en su ejemplo.

La segunda cosa a tener en cuenta es la confusión resultante del uso del idnombre genérico para un atributo.

Lo CustomerOrderNoideal sería (1,2,3 ..) para cada cliente y OrderItemNo(1,2,3 ...) para cada pedido.

Bueno, esto es bueno si es posible, pero requiere una consulta que busque el valor máximo anterior, como

select max(CustomerOrderNo)
from Order 
where CustomerID = specific_customer ; 

que a menudo no se prefiere en entornos de alto volumen de transacciones, por lo que es común ver estos reemplazados por un incremento automático, que esencialmente sirve para el mismo propósito. Es cierto que este incremento automático ahora es único, por lo tanto, puede usarse como una CLAVE, pero puede optar por considerarlo como un compromiso necesario para el OrderItemNo.

Entonces, con algunos cambios de nombre CustomerOrderNo -> OrderNoy OrderItemNo-> ItemNopuede llegar a este modelo

ingrese la descripción de la imagen aquí

Entonces, si nos fijamos en Orderlo siguiente, son únicos

{OrderNo}             -- PK
{CustomerID, OrderNo} -- superkey,  AK on the diagram.

Tenga en cuenta que {CustomerID, OrderNo}se propaga a la LineItempara servir como un FK.

Si entrecierra un poco los ojos, esto está cerca de su ejemplo, pero PKs {ItemNo} and {OrderNo}solo con , en lugar de dos PK de columna de su ejemplo.

Ahora la pregunta es, ¿por qué no simplificar a algo como esto?

ingrese la descripción de la imagen aquí

Lo cual está bien, pero introduce dependencia de la trayectoria - no se puede unir LineItemcon Customerdirectamente, debe utilizar Orderen la combinación.


Prefiero el primer caso cuando sea posible: eliges tu favorito. Y obviamente, no hay necesidad de FK directo de LineItema Customeren estos tres casos.

Damir Sudarevic
fuente
Busqué alrededor, pero no puedo ver que "dependencia de ruta" se use como un término ampliamente adoptado para lo que me referiría como "relación transitiva de segundo grado" (aunque mi terminología probablemente también sea incorrecta)
Dai
2

El "artículo" no debe hacer referencia al "cliente" directamente, porque esto está implícito en el "pedido" del artículo. Por lo tanto, no necesitará las columnas "cliente" en la tabla de "artículos".

La relación del artículo con el cliente se garantiza con la clave externa existente.

Si orders.id es una columna de identidad, considere eliminar items.customer por completo.

Daniel Hutmacher
fuente
1
Gracias, no me di cuenta de que "cliente" también se incluyó en el primer FK de "artículos" a "pedidos". He elaborado mi respuesta en consecuencia.
Daniel Hutmacher
@DanielHutmacher He editado la pregunta para que contenga las claves principales de mis tablas. Esto explica los extraños FK que mencionas en tu edición.
vektor
Ok, he actualizado mi respuesta. :)
Daniel Hutmacher
Supongo que tener customeren todas las tablas (y, por lo tanto, aislar el DB) es un enfoque inusual. Debo confesar que es algo que he visto en mi trabajo anterior. ¿Tiene algún sentido para ti? ¿Has visto tal diseño antes?
vektor
Yo diría que parece un enfoque de datawarehouse (esquema en estrella), donde desea desnormalizar intencionalmente los datos para eliminar las uniones. O la clave principal podría ser compuesta, es decir, el primer, segundo, tercer orden del cliente A, el primer, segundo orden del cliente B, etc., cuando la columna de identificación del pedido por sí sola no es única.
Daniel Hutmacher