¿Cuándo / por qué usar cascada en SQL Server?

149

Al configurar claves externas en SQL Server, ¿en qué circunstancias debería tenerlo en cascada al eliminar o actualizar, y cuál es el razonamiento detrás de esto?

Esto probablemente también se aplica a otras bases de datos.

Estoy buscando sobre todo ejemplos concretos de cada escenario, preferiblemente de alguien que los haya usado con éxito.

Joel Coehoorn
fuente
44
Esta pregunta no parece estar estrictamente relacionada con SQL Server y se parece más a una pregunta teórica y general. Sería más útil para la comunidad si elimina la sql-serveretiqueta.
clapas
44
@clapas Honestamente, si tuviera que preguntarlo hoy, estaría fuera de tema. Si no fuera por las altas vistas / votos que indican que tiene valor para la comunidad, simplemente lo eliminaría.
Joel Coehoorn el
66
@JoelCoehoorn: obviamente, este tipo de preguntas tienen valor. Este valor no se disipa debido al paso del tiempo. La pregunta en mi mente es ¿cuánto valor estamos perdiendo al no permitir tales preguntas hoy?
P.Brian.Mackey
2
@ P.Brian.Mackey ¡Aquí, aquí! Algunas de las mejores preguntas / respuestas que he visto son aquellas que han sido rechazadas o pintadas como fuera de tema ... ¡pero por la ENORME cantidad de votos positivos, muchos han tenido exactamente la misma pregunta!
Anthony Griggs el
Las acciones en cascada toman bloqueos serializables.
Mitch Wheat

Respuestas:

126

Resumen de lo que he visto hasta ahora:

  • A algunas personas no les gusta la cascada

Eliminar en cascada

  • Cascade Delete puede tener sentido cuando la semántica de la relación puede involucrar una descripción exclusiva "es parte de ". Por ejemplo, un registro de OrderLine es parte de su pedido principal, y OrderLines nunca se compartirá entre varios pedidos. Si la orden se desvaneciera, la línea de orden también debería, y una línea sin una orden sería un problema.
  • El ejemplo canónico para Cascade Delete es SomeObject y SomeObjectItems, donde no tiene ningún sentido que exista un registro de elementos sin un registro principal correspondiente.
  • Usted debe no utilizar Eliminar en cascada si desea conservar la historia o el uso de un "soft / borrado lógico" donde sólo se configura una columna poco borrado a 1 / verdad.

Actualización en cascada

  • La actualización en cascada puede tener sentido cuando utiliza una clave real en lugar de una clave sustituta (columna de identidad / incremento automático) en las tablas.
  • El ejemplo canónico de Cascade Update es cuando tiene una clave externa mutable, como un nombre de usuario que se puede cambiar.
  • Usted debe no utilizar Actualizar en cascada con claves que son de Identidad / columnas autoincrement.
  • La actualización en cascada se utiliza mejor junto con una restricción única.

Cuándo usar en cascada

  • Es posible que desee obtener una confirmación extra fuerte del usuario antes de permitir que una operación en cascada, pero depende de su aplicación.
  • La conexión en cascada puede meterlo en problemas si configura mal sus claves externas. Pero deberías estar bien si haces eso bien.
  • No es aconsejable utilizar la cascada antes de comprenderla a fondo. Sin embargo, es una característica útil y, por lo tanto, vale la pena tomarse el tiempo para comprender.
Joel Coehoorn
fuente
3
Tenga en cuenta que las actualizaciones en cascada también se usan a menudo donde las "llamadas" teclas naturales parecen no ser estas teclas únicas realmente efectivas. De hecho, estoy convencido de que las actualizaciones en cascada solo se necesitan con modelos de bases de datos mal normalizados, y son una puerta abierta a tablas y códigos desordenados.
Philippe Grondier el
1
Se está perdiendo un punto importante, la conexión en cascada puede crear enormes problemas de rendimiento si hay muchos registros secundarios.
HLGEM
13
@HLGEM - No veo la relevancia. Si las operaciones en cascada provocan una desaceleración, el proceso manual equivalente provocaría la misma desaceleración o no se protegería correctamente en caso de que la transacción deba revertirse.
Joel Coehoorn
3
¿Por qué importaría si hay una actualización en cascada en una columna IDENTITY o auto-increment? Puedo ver por qué no sería necesario , ya que no es necesario cambiar esos valores (arbitrarias), pero si uno de ellos hizo el cambio, al menos, la integridad referencial estaría intacta.
Kenny Evitt
3
10 balas? Bueno, ahora sabemos que Joel no está disparando un revólver.
Neil N
68

Las claves externas son la mejor manera de garantizar la integridad referencial de una base de datos. Evitar las cascadas por ser mágico es como escribir todo en ensamblado porque no confías en la magia detrás de los compiladores.

Lo malo es el uso incorrecto de claves externas, como crearlas al revés, por ejemplo.

El ejemplo de Juan Manuel es el ejemplo canónico, si usa código hay muchas más posibilidades de dejar documentos falsos en la base de datos que vendrán y lo morderán.

Las actualizaciones en cascada son útiles, por ejemplo, cuando tiene referencias a los datos por algo que puede cambiar, digamos que una clave principal de una tabla de usuarios es la combinación de nombre y apellido. Luego, desea que los cambios en esa combinación se propaguen a donde se haga referencia.

@Aidan, esa claridad a la que te refieres tiene un alto costo, la posibilidad de dejar datos espurios en tu base de datos, que no es pequeña . Para mí, generalmente es la falta de familiaridad con el DB y la incapacidad de encontrar qué FK están en su lugar antes de trabajar con el DB lo que fomenta ese miedo. O eso, o el mal uso constante de la cascada, usándolo donde las entidades no estaban relacionadas conceptualmente, o donde tienes que preservar la historia.

Vinko Vrsalovic
fuente
77
Usar ese tipo de clave primaria 'natural' es una idea realmente pobre en primer lugar.
Nick Johnson el
44
RE: Comentario dirigido a Aidan. No, dejar CASCADE en un FK no aumenta la posibilidad de dejar datos falsos. Disminuye la posibilidad de que un comando afecte más datos de lo esperado y aumenta el código. Dejar fuera a los FK por completo deja una posibilidad de datos espurios.
Shannon Severance
55
Al haber visto al menos dos veces en mi carrera las consecuencias que amenazan el negocio de una eliminación en cascada incomprendida, no estoy dispuesto a usarlas en todos, excepto en los casos más claros. En ambos casos, los datos se eliminaron como resultado de una cascada que realmente debería haberse retenido pero no se detectó, y que faltaba no se detectó hasta que el ciclo normal de copia de seguridad había perdido la posibilidad de una restauración fácil. Vinko es correcto desde un punto de vista puramente lógico, sin embargo, en el mundo real el uso de cascadas lo expone a la falibilidad humana y a las consecuencias imprevistas más de lo que me gustaría.
Cruachan
1
De hecho, he codificado sistemas en los que se ha tomado una decisión de gestión de que los usuarios tendrán que eliminar explícitamente a todos los niños en un detalle maestro antes de que puedan eliminar el maestro simplemente para obligar al usuario a pensar. No usar cascadas cuando lógicamente se podría es un tipo similar de cortafuegos.
Cruachan
66
@Cruachan: La regla, en mi opinión, es simple. Si los datos no están tan fuertemente relacionados como para ser inútiles sin los datos principales, entonces no garantiza una relación en cascada. Esto es lo que intenté abordar en la última frase de mi respuesta.
Vinko Vrsalovic
17

Nunca uso eliminaciones en cascada.

Si quiero que se elimine algo de la base de datos, quiero decirle explícitamente a la base de datos lo que quiero sacar.

Por supuesto, son una función disponible en la base de datos y puede haber ocasiones en las que está bien usarlas, por ejemplo, si tiene una tabla 'order' y una tabla 'orderItem', es posible que desee borrar los elementos cuando elimina un orden.

Me gusta la claridad que obtengo al hacerlo en código (o procedimiento almacenado) en lugar de que ocurra 'magia'.

Por la misma razón, tampoco soy fanático de los desencadenantes.

Algo a tener en cuenta es que si elimina un 'pedido', recibirá un informe de '1 fila afectada' incluso si la eliminación en cascada ha eliminado 50 'artículos de pedido.

Loofer
fuente
34
¿Por qué no deshacerse de las claves primarias también? Obtendría la claridad de garantizar valores únicos en su código.
MusiGenesis
44
@MusiGenesis, Aidan no estaba abogando por eliminar el FK. El FK todavía protege los datos, pero sin CASCADE ON ... no ocurre magia inesperada.
Shannon Severance
77
@Vinko: Eliminar y actualizar tienen una semántica predeterminada bien definida. Cambiar el comportamiento a través de una cascada o un disparador para hacer más trabajo deja una posibilidad de que se haya hecho más de lo previsto. No, no trabajo sin probar y sí, mis bases de datos están documentadas. ¿Pero recuerdo cada pieza de documentación mientras escribía el código? Si quiero una semántica de nivel superior, como eliminar padre e hijos, escribiré y usaré un SP para hacerlo.
Shannon Severance
3
@Vinko. El problema de la magia no es con los desarrolladores competentes o los DBA, sino con Joe Interen, 5 años después, a quien se le ha dado una tarea de mantenimiento 'simple' cuando el DBA está de vacaciones y luego arruina los datos corporativos sin que nadie se dé cuenta. Las cascadas tienen su lugar, pero es importante considerar todas las circunstancias, incluidos los factores humanos, antes de desplegarlas.
Cruachan
55
@Vinko: ¿Por qué 'SP' de Gasp? Los SP son definitivamente el camino a seguir donde la base de datos es un activo corporativo crítico. Existe un fuerte argumento en el tipo de circunstancias de las que se hablaba para restringir todos los accesos de datos a los SP, o al menos a todos excepto a Select. Vea mi respuesta en stackoverflow.com/questions/1171769/…
Cruachan
13

Trabajo mucho con eliminaciones en cascada.

Se siente bien saber que quien trabaja en contra de la base de datos nunca podría dejar datos no deseados. Si las dependencias crecen, solo cambio las restricciones en el diagrama en Management Studio y no tengo que ajustar sp o dataacces.

Dicho esto, tengo 1 problema con las eliminaciones en cascada y esas son referencias circulares. Esto a menudo conduce a partes de la base de datos que no tienen eliminaciones en cascada.

Mathias F
fuente
1
Sé que esto es muy antiguo, pero +1 por mencionar el problema de referencia circular con CASCADE DELETE.
Código Maverick
2
Disculpe una pregunta novata: ¿qué sucede realmente si obtiene una referencia circular?
Tim Lovell-Smith
10

Hago mucho trabajo de base de datos y rara vez encuentro útiles las eliminaciones en cascada. La única vez que los he usado de manera efectiva es en una base de datos de informes que se actualiza mediante un trabajo nocturno. Me aseguro de que los datos modificados se importen correctamente eliminando los registros de nivel superior que hayan cambiado desde la última importación, luego vuelvo a importar los registros modificados y todo lo relacionado con ellos. Me ahorra tener que escribir muchas eliminaciones complicadas que se ven desde abajo hacia arriba en mi base de datos.

No considero que las eliminaciones en cascada sean tan malas como los desencadenantes, ya que solo eliminan datos, los desencadenantes pueden tener todo tipo de cosas desagradables dentro.

En general, evito las eliminaciones reales por completo y utilizo eliminaciones lógicas (es decir, tener una columna de bits llamada isDeleted que se establece en verdadero) en su lugar.

Martynnw
fuente
2
Tienes curiosidad por aprender un poco más. ¿Por qué prefiere fuertemente las eliminaciones lógicas? ¿Los datos con los que está trabajando tienen algo que ver?
Tim Lovell-Smith
9

Un ejemplo es cuando tiene dependencias entre entidades ... es decir: Documento -> DocumentItems (cuando elimina Document, DocumentItems no tiene una razón para existir)

juan
fuente
5

Utilice la eliminación en cascada donde desea que se elimine el registro con el FK si se eliminó su registro PK de referencia. En otras palabras, donde el registro no tiene sentido sin el registro de referencia.

Considero que la eliminación en cascada es útil para garantizar que las referencias muertas se eliminen de forma predeterminada en lugar de causar excepciones nulas.

patrón de prueba
fuente
5

ON Eliminar cascada:

Cuando desee que se eliminen las filas de la tabla secundaria Si la fila correspondiente se elimina en la tabla primaria.

Si no se utiliza la eliminación en cascada, se generará un error de integridad referencial .

Cascada de actualización ON:

Cuando desee que el cambio en la clave primaria se actualice en clave externa

Durai Amuthan.H
fuente
5

He oído hablar de DBA y / o "Política de la empresa" que prohíbe el uso de "On Delete Cascade" (y otros) simplemente debido a malas experiencias en el pasado. En un caso, un chico escribió tres disparadores que terminaron llamándose unos a otros. Tres días para recuperarse resultaron en una prohibición total de los disparadores, todo debido a las acciones de un idjit.

Por supuesto, a veces se necesitan desencadenantes en lugar de "On Delete cascade", como cuando es necesario preservar algunos datos secundarios. Pero en otros casos, es perfectamente válido usar el método en cascada On Delete. Una ventaja clave de "On Delete Cascade" es que captura TODOS los niños; un procedimiento de almacenamiento / disparo escrito personalizado puede no funcionar si no está codificado correctamente.

Creo que se debería permitir que el Desarrollador tome la decisión basándose en lo que es el desarrollo y lo que dice la especificación. Una prohibición de la alfombra basada en una mala experiencia no debería ser el criterio; el proceso de pensamiento "Nunca usar" es draconiano en el mejor de los casos. Se debe hacer una llamada de juicio cada vez, y se deben hacer cambios a medida que cambia el modelo de negocio.

¿No es esto de lo que se trata el desarrollo?

BrianBurkill
fuente
No pensé que eliminaría todo ... ¿quieres decir que la función realmente hace lo que dice que hace? ...
Joel Coehoorn
3

Una razón para poner una eliminación en cascada (en lugar de hacerlo en el código) es mejorar el rendimiento.

Caso 1: con una eliminación en cascada

 DELETE FROM table WHERE SomeDate < 7 years ago;

Caso 2: sin una eliminación en cascada

 FOR EACH R IN (SELECT FROM table WHERE SomeDate < 7 years ago) LOOP
   DELETE FROM ChildTable WHERE tableId = R.tableId;
   DELETE FROM table WHERE tableId = R.tableid;
   /* More child tables here */
 NEXT

En segundo lugar, cuando agrega una tabla secundaria adicional con una eliminación en cascada, el código en el Caso 1 sigue funcionando.

Solo pondría en una cascada donde la semántica de la relación es "parte de". De lo contrario, algún idiota eliminará la mitad de su base de datos cuando lo haga:

DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'
WW.
fuente
55
Sin saber qué base de datos usa, sugeriría que su eliminación manual tenga un rendimiento peor que la eliminación en cascada porque no está establecida. En la mayoría de las bases de datos, puede eliminar en función de una unión a otra tabla y, por lo tanto, tener una eliminación basada en conjuntos y mucho más rápida que recorrer los registros.
HLGEM
2

Intento evitar eliminaciones o actualizaciones que no solicité explícitamente en el servidor SQL.

Ya sea en cascada o mediante el uso de disparadores. Tienden a morderte el culo en algún momento, ya sea al intentar localizar un error o al diagnosticar problemas de rendimiento.

Donde los usaría es para garantizar la consistencia por poco esfuerzo. Para obtener el mismo efecto, tendría que usar procedimientos almacenados.

pauliephonic
fuente
2

Yo, como todos los demás aquí, encuentro que las eliminaciones en cascada son realmente solo marginalmente útiles (realmente no es mucho trabajo eliminar datos referenciados en otras tablas; si hay muchas tablas, simplemente automatizas esto con un script) pero realmente molesto cuando alguien en cascada accidentalmente elimina algunos datos importantes que son difíciles de restaurar.

El único caso en el que usaría es si los datos en la tabla de la tabla están altamente controlados (por ejemplo, permisos limitados) y solo se actualizan o eliminan a través de un proceso controlado (como una actualización de software) que se ha verificado.

Jen A
fuente
1

Una eliminación o actualización de S que elimine un valor de clave externa que se encuentra en algunas tuplas de R se puede manejar de una de estas tres maneras:

  1. Rechazo
  2. Propagación
  3. anulación.

La propagación se conoce como cascada.

Hay dos casos:

‣ Si se eliminó una tupla en S, elimine las tuplas R que se refieren a ella.

‣ Si se actualizó una tupla en S, actualice el valor en las tuplas R que se refieren a ella.

Mayank Chopra
fuente
0

Si está trabajando en un sistema con muchos módulos diferentes en diferentes versiones, puede ser muy útil, si los elementos eliminados en cascada son parte del titular de PK o son de su propiedad. De lo contrario, todos los módulos requerirían parches inmediatos para limpiar sus elementos dependientes antes de eliminar el propietario de PK, o la relación de clave externa se omitiría por completo, posiblemente dejando toneladas de basura en el sistema si la limpieza no se realiza correctamente.

Acabo de introducir la eliminación en cascada para una nueva tabla de intersección entre dos tablas ya existentes (solo la intersección para eliminar), después de que se haya desaconsejado la eliminación en cascada durante bastante tiempo. Tampoco es tan malo si se pierden los datos.

Sin embargo, es algo malo en las tablas de lista tipo enumeración: alguien elimina la entrada 13: amarillo de los "colores" de la tabla, y todos los elementos amarillos en la base de datos se eliminan. Además, estos a veces se actualizan de una manera delete-all-insert-all, lo que lleva a una integridad referencial totalmente omitida. Por supuesto que está mal, pero ¿cómo va a cambiar un software complejo que ha estado funcionando durante muchos años, con la introducción de una verdadera integridad referencial que corre el riesgo de sufrir efectos secundarios inesperados?

Otro problema es cuando los valores de la clave externa original se mantendrán incluso después de que se haya eliminado la clave primaria. Se puede crear una columna de lápida y una opción ON DELETE SET NULL para el FK original, pero esto nuevamente requiere disparadores o código específico para mantener el valor de clave redundante (excepto después de la eliminación de PK).

Erik Hart
fuente
0

Las eliminaciones en cascada son extremadamente útiles cuando se implementan entidades lógicas de supertipo y subtipo en una base de datos física.

Cuando se utilizan tablas separadas de supertipo y subtipo para implementar físicamente supertipos / subtipos (en lugar de agrupar todos los atributos de subtipo en una sola tabla física de supertipo), hay una -una relación entre estas tablas y el problema se convierte en cómo mantener las claves primarias 100% sincronizadas entre estas tablas.

Las eliminaciones en cascada pueden ser una herramienta muy útil para:

1) Asegúrese de que al eliminar un registro de supertipo también se elimina el registro de subtipo único correspondiente.

2) Asegúrese de que cualquier eliminación de un registro de subtipo también elimina el registro de supertipo. Esto se logra mediante la implementación de un desencadenador de eliminación "en lugar de" en la tabla de subtipos que va y elimina el registro de supertipo correspondiente, que, a su vez, en cascada elimina el registro de subtipo.

El uso de eliminaciones en cascada de esta manera garantiza que nunca existan registros huérfanos de supertipo o subtipo, independientemente de si elimina primero el registro de supertipo o el registro de subtipo.

Mark Allen
fuente
Buen ejemplo. En JPA, es InheritanceStrategy Joined Table. Para 1): Normalmente, está utilizando un marco de capa de persistencia (EclipseLink, Hibernate, ...), que implementa la secuencia eliminada para que una entidad unida elimine primero la parte unida, luego la superparte. Pero si tiene un software más básico, como un trabajo de importación o archivo, es conveniente poder simplemente eliminar la entidad emitiendo una eliminación en la parte superior. Con respecto a 2): de acuerdo, pero en ese caso el cliente ya debe saber que está trabajando en una parte unida / sub de la entidad.
leo