Pregunta

En MSSQL 2005 acabo de dar con el infame mensaje de error:

  

Introducir la restricción FOREIGN KEY XXX en la tabla YYY puede causar ciclos o múltiples rutas en cascada. Especifique ON DELETE NO ACTION o ON UPDATE NO ACTION, o modifique otras restricciones de FOREIGN KEY.

Ahora, StackOverflow tiene varios temas sobre este mensaje de error, por lo que ya tengo la solución (en mi caso, tendré que usar desencadenantes), pero tengo curiosidad de por qué hay tal problema. .

Según tengo entendido, básicamente hay dos escenarios que quieren evitar: un ciclo y múltiples rutas. Un ciclo sería donde dos tablas tienen claves foráneas en cascada entre sí. OK, un ciclo también puede abarcar varias tablas, pero este es el caso básico y será más fácil de analizar.

Serían múltiples rutas cuando TableA tiene claves foráneas para TableB y TableC, y TableB también tiene una clave foránea para TableC. Nuevamente, este es el caso básico mínimo.

No puedo ver ningún problema que surja cuando un registro se elimine o actualice en cualquiera de esas tablas. Claro, es posible que deba consultar la misma tabla varias veces para ver qué registros deben actualizarse / eliminarse, pero ¿es realmente un problema? ¿Es esto un problema de rendimiento?

En otros temas SO, las personas llegan a etiquetar usando cascadas como " arriesgado " y declara que " resolver rutas en cascada es una problema complejo " ;. ¿Por qué? ¿Dónde está el riesgo? ¿Dónde está el problema?

¿Fue útil?

Solución

Tiene una tabla secundaria con 2 rutas en cascada del mismo elemento primario: una " eliminar " ;, una " nula " ;.

¿Qué tiene prioridad? ¿Qué esperas después? etc.

Nota: Un disparador es código y puede agregar algo de inteligencia o condiciones a una cascada.

Otros consejos

La razón por la que prohibimos usar la eliminación en cascada tiene que ver con el rendimiento y el bloqueo. Sí, no es tan malo cuando elimina un registro, pero tarde o temprano tendrá que eliminar un gran grupo de registros y su base de datos se detendrá.

Si está eliminando suficientes registros, SQL Server puede escalar a un bloqueo de tabla y nadie puede hacer nada con la tabla hasta que finalice.

Recientemente trasladamos a uno de nuestros clientes a su propio servidor. Como parte del acuerdo, también tuvimos que eliminar todos los registros de ese cliente de nuestro servidor original. Eliminar toda su información en lotes (para no causar problemas con otros usuarios) tomó un par de meses. Si hubiéramos configurado la eliminación en cascada, la base de datos habría estado inaccesible para los otros clientes durante mucho tiempo, ya que millones de registros se eliminaron en una transacción y cientos de tablas se bloquearon hasta que se realizó la transacción.

También pude ver un escenario en el que podría haberse producido un punto muerto al usar la eliminación en cascada porque no tenemos control sobre el orden que habría tomado la ruta en cascada y nuestra base de datos está algo desnormalizada con el ID de cliente que aparece en la mayoría de las tablas. Entonces, si bloqueó la tabla que tenía una clave externa también en una tercera tabla, así como la tabla del cliente que estaba en una ruta diferente, posiblemente no podría verificar esa tabla para eliminarla de la tercera tabla porque esto es todo una transacción y los bloqueos no se liberarían hasta que se realizara. Entonces, posiblemente no nos habría permitido configurar eliminaciones en cascada si hubiera visto la posibilidad de crear puntos muertos en la transacción.

Otra razón para evitar eliminaciones en cascada es que a veces la existencia de un registro secundario es razón suficiente para no eliminar el registro primario. Por ejemplo, si tiene una tabla de clientes y ese cliente ha tenido pedidos en el pasado, no querrá eliminarlo y perder la información del pedido real.

Considere una tabla de empleados:

CREATE TABLE Employee
(
    EmpID   INTEGER NOT NULL PRIMARY KEY,
    Name    VARCHAR(40) NOT NULL,
    MgrID   INTEGER NOT NULL REFERENCES Employee(EmpID) ON DELETE CASCADE
);

INSERT INTO Employees(     1, "Bill",   1);
INSERT INTO Employees(    23, "Steve",  1);
INSERT INTO Employees(234212, "Helen", 23);

Ahora suponga que Bill se retira:

DELETE FROM Employees WHERE Name = "Bill";

Ooooppps; ¡Todos fueron despedidos!

[ Podemos debatir si los detalles de la sintaxis son correctos; el concepto se mantiene, creo. ]

Creo que el problema es que cuando haces una ruta " ON DELETE CASCADE " y el otro '' AL BORRAR RESTRICCIÓN '', o '' SIN ACCIÓN '' El resultado (el resultado) es impredecible. Depende de qué disparador de eliminación (esto también es un disparador, pero uno que no tiene que construir usted mismo) se ejecutará primero.

Estoy de acuerdo con que las cascadas sean "arriesgadas" y debe ser evitado (Personalmente prefiero poner en cascada los cambios de forma manual en lugar de tener un servidor SQL que se encargue de ellos automáticamente). Esto también se debe a que incluso si el servidor sql eliminara millones de filas, la salida aún se mostraría como

(1 fila (s) afectada)

Creo que si usar o no una opción ON DELETE CASCADE es una cuestión del modelo de negocio que está implementando. Una relación entre dos objetos comerciales podría ser una simple "asociación", donde ambos extremos de la relación están relacionados, pero por lo demás son objetos independientes cuyo ciclo de vida es diferente y está controlado por otra lógica. Sin embargo, también hay "agregación". relaciones, donde un objeto podría verse realmente como el "padre" o "propietario" de un "niño" o "detalle" objeto. Existe la noción aún más fuerte de una `` composición '' relación, donde un objeto existe únicamente como una composición de varias partes. En la "asociación" caso, generalmente no declarará una restricción ON DELETE CASCADE. Sin embargo, para agregaciones o composiciones, ON DELETE CASCADE lo ayuda a mapear su modelo de negocio a la base de datos de manera más precisa y declarativa. Es por eso que me molesta que MS SQL Server restrinja el uso de esta opción a una única ruta en cascada. Si no me equivoco, muchos otros sistemas de bases de datos SQL ampliamente utilizados no imponen tales restricciones.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top