Quando / Por que usar o Cascading no SQL Server?


149

Ao configurar chaves estrangeiras no SQL Server, sob quais circunstâncias você deve fazê-lo em cascata ao excluir ou atualizar, e qual é o motivo por trás disso?

Isso provavelmente se aplica a outros bancos de dados também.

Estou procurando sobretudo exemplos concretos de cada cenário, de preferência de alguém que os tenha usado com sucesso.


4
Esta pergunta não parece estritamente relacionada ao SQL Server e parece mais uma pergunta teórica geral. Seria mais útil para a comunidade se você remover a sql-servertag.
clapas 23/08

4
@clapas Honestamente, se eu perguntasse hoje, estaria fora de assunto. Se não fosse pelas altas visualizações / votos, indicando que ele tem valor para a comunidade, eu apenas a excluiria.
Joel Coehoorn

6
@ JoelCoehoorn - Obviamente, esses tipos de perguntas têm valor. Este valor não se dissipa devido à passagem do tempo. A questão em minha mente é quanto valor estamos perdendo ao proibir tais perguntas hoje?
precisa

2
@ P.Brian.Mackey Aqui, Aqui! Algumas das melhores perguntas / respostas que eu vi são aquelas que foram votadas para baixo ou pintadas como fora de tópico ... mas você pode dizer pela enorme quantidade de votos que muitos tiveram a mesma pergunta!
Anthony Griggs

Ações em cascata recebem bloqueios serializáveis.
Mitch Wheat

Respostas:


126

Resumo do que vi até agora:

  • Algumas pessoas não gostam de cascata.

Excluir em cascata

  • A exclusão em cascata pode fazer sentido quando a semântica do relacionamento puder envolver uma descrição exclusiva "faz parte da ". Por exemplo, um registro OrderLine faz parte do seu pedido pai e o OrderLines nunca será compartilhado entre vários pedidos. Se o Pedido desaparecer, o OrderLine também deve, e uma linha sem um Pedido seria um problema.
  • O exemplo canônico de Exclusão em cascata é SomeObject e SomeObjectItems, onde não faz sentido que um registro de itens exista sem um registro principal correspondente.
  • Você não deve usar a exclusão em cascata se estiver preservando o histórico ou usando uma "exclusão lógica / lógica" onde apenas define uma coluna de bit excluída como 1 / true.

Atualização em cascata

  • A atualização em cascata pode fazer sentido quando você usa uma chave real em vez de uma chave substituta (coluna de identidade / incremento automático) nas tabelas.
  • O exemplo canônico da atualização em cascata é quando você tem uma chave estrangeira mutável, como um nome de usuário que pode ser alterado.
  • Você não deve usar o Cascade Update com chaves que são colunas de identidade / incremento automático.
  • A atualização em cascata é melhor usada em conjunto com uma restrição exclusiva.

Quando usar em cascata

  • Convém obter uma confirmação extra forte do usuário antes de permitir uma operação em cascata, mas isso depende do seu aplicativo.
  • A cascata pode causar problemas se você configurar incorretamente suas chaves estrangeiras. Mas você deve ficar bem se fizer isso direito.
  • Não é aconselhável usar a cascata antes de entender completamente. No entanto, é um recurso útil e, portanto, vale a pena dedicar algum tempo para entender.

3
Observe que as atualizações em cascata também costumam ser usadas onde as "chamadas" chaves naturais parecem não ser essas chaves únicas efetivas. Na verdade, estou convencido de que as atualizações em cascata são necessárias apenas com modelos de banco de dados mal normalizados e são um portão aberto para tabelas e códigos bagunçados.
Philippe Grondier

1
Está faltando um ponto importante: a cascata pode criar enormes problemas de desempenho se houver muitos registros filhos.
HLGEM 14/05

13
@HLGEM - Não vejo a relevância. Se uma operação em cascata causar uma desaceleração, o processo manual equivalente causaria a mesma desaceleração ou não seria corretamente protegido caso a transação precise ser revertida.
Joel Coehoorn

3
Por que importa se há uma atualização em cascata em uma coluna de IDENTITY ou de incremento automático? Eu posso ver porque não seria necessário porque você não deve precisar alterar esses valores (arbitrárias), mas se um deles fez a mudança, pelo menos, a integridade referencial seria intacta.
Kenny Evitt

3
10 balas? Bem, agora sabemos que Joel não está disparando um revólver.
Neil N

68

Chaves estrangeiras são a melhor maneira de garantir a integridade referencial de um banco de dados. Evitar cascatas por ser mágico é como escrever tudo em montagem, porque você não confia na mágica por trás dos compiladores.

O que é ruim é o uso incorreto de chaves estrangeiras, como criá-las ao contrário, por exemplo.

O exemplo de Juan Manuel é o exemplo canônico, se você usar código, há muito mais chances de deixar DocumentItems espúrios no banco de dados que aparecerão e morderão você.

As atualizações em cascata são úteis, por exemplo, quando você tem referências aos dados por algo que pode mudar, digamos que uma chave primária de uma tabela de usuários seja o nome, a combinação de sobrenome. Então você deseja que as alterações nessa combinação sejam propagadas para onde quer que sejam referenciadas.

@Aidan, essa clareza a que você se refere tem um alto custo, a chance de deixar dados espúrios no seu banco de dados, o que não é pequeno . Para mim, geralmente é apenas a falta de familiaridade com o DB e a incapacidade de descobrir quais FKs existem antes de trabalhar com o DB que fomentam esse medo. Ou isso, ou uso indevido constante de cascata, usando-o onde as entidades não estavam conceitualmente relacionadas ou onde você precisa preservar a história.


7
Usar esse tipo de chave primária "natural" é uma péssima idéia em primeiro lugar.
21411 Nick Johnson

4
RE: Comentário dirigido a Aidan. Não, deixar CASCADE em um FK não aumenta a chance de deixar dados espúrios. Isso diminui a chance de mais dados serem impactados por um comando do que o esperado e aumenta o código. Deixar os FKs inteiramente deixa uma chance de dados espúrios.
Shannon Severance

5
Tendo visto pelo menos duas vezes na minha carreira, as conseqüências ameaçadoras aos negócios de uma exclusão em cascata incompreendida, estou muito pouco inclinado a usá-las em todos, exceto nos casos mais claros. Nos dois casos, os dados foram excluídos como resultado de uma cascata que realmente deveria ter sido mantida, mas não foi - e que estava faltando, não foi detectada até que o ciclo normal de backup tivesse perdido a possibilidade de uma restauração fácil. Vinko está correto do ponto de vista puramente lógico, no entanto, no mundo real, o uso de cascatas expõe a pessoa à falibilidade humana e às consequências imprevisíveis mais do que eu gostaria.
Cruachan 27/05

1
Na verdade, eu codifiquei sistemas em que foi tomada uma decisão de gerenciamento de que os usuários terão que excluir explicitamente todos os filhos em um detalhe mestre antes de poderem excluir o mestre simplesmente para forçar o usuário a pensar. Não usar cascatas quando logicamente é possível é um tipo semelhante de quebra de incêndio.
Cruachan

6
@Cruachan: A regra, na minha opinião, é simples. Se os dados não estiverem tão fortemente relacionados a ponto de serem inúteis sem os dados pai, eles não justificam um relacionamento em cascata. É isso que tentei abordar na última frase da minha resposta.
Vinko Vrsalovic 28/05

17

Eu nunca uso exclusões em cascata.

Se eu quiser remover algo do banco de dados, quero explicitamente informar ao banco de dados o que quero remover.

É claro que elas são uma função disponível no banco de dados e pode haver momentos em que é bom usá-las, por exemplo, se você tiver uma tabela 'order' e uma tabela 'orderItem', poderá limpar os itens ao excluir um ordem.

Eu gosto da clareza que recebo ao fazê-lo no código (ou procedimento armazenado), em vez de acontecer 'mágica'.

Pela mesma razão, também não sou fã de gatilhos.

Algo a notar é que, se você excluir um 'pedido', receberá o relatório '1 linha afetada' de volta, mesmo que a exclusão em cascata tenha removido 50 'itens do pedido.


34
Por que não se livrar das chaves primárias também? Você terá a clareza de garantir valores exclusivos no seu código.
MusiGenesis

4
@MusiGenesis, Aidan não estava defendendo a remoção do FK. O FK ainda protege os dados, mas sem o CASCADE ON .... mágica inesperada não acontece.
Shannon Severance

7
@Vinko: Excluir e atualizar têm semânticas padrão bem definidas. Alterar o comportamento por meio de uma cascata ou gatilho para fazer mais trabalho deixa uma chance de que mais foi feito do que o pretendido. Não, não trabalho sem testar e sim meus bancos de dados estão documentados. Mas lembro-me de toda a documentação ao escrever o código? Se eu quiser uma semântica de nível superior, como excluir pai e filhos, escreverei e usarei um SP para fazer isso.
Shannon Severance

3
@Vinko. o problema da mágica não é com desenvolvedores competentes ou DBAs, é com Joe interen, cinco anos depois, quem recebe uma tarefa de manutenção "simples" quando o DBA está de férias e que depois estraga os dados corporativos sem que ninguém perceba. As cascatas têm seu lugar, mas é importante considerar todas as circunstâncias, incluindo fatores humanos, antes de implantá-las.
Cruachan 27/05

5
@Vinko: Por que SPs 'Gasp'? Os SPs são desafiadores o caminho a percorrer, onde o banco de dados é um ativo corporativo crítico. Há um forte argumento no tipo de circunstância em que estamos falando para restringir todos os acessos de dados aos SPs, ou pelo menos todos, exceto Select. Veja minha resposta em stackoverflow.com/questions/1171769/…
Cruachan

13

Eu trabalho muito com exclusões em cascata.

É bom saber quem trabalha com o banco de dados nunca pode deixar dados indesejados. Se as dependências crescem, apenas altero as restrições no diagrama no Management Studio e não preciso ajustar sp ou dados.

Dito isto, eu tenho um problema com exclusões em cascata e isso é referências circulares. Isso geralmente leva a partes do banco de dados que não têm exclusões em cascata.


1
Sei que isso é muito antigo, mas +1 por mencionar o problema de referência circular no CASCADE DELETE.
Code Maverick

2
Perdoe uma pergunta noob: o que realmente acontece se você receber uma referência circular?
Tim Lovell-Smith

10

Faço muito trabalho no banco de dados e raramente considero as exclusões em cascata úteis. A única vez em que os usei efetivamente está em um banco de dados de relatórios atualizado por um trabalho noturno. Asseguro que todos os dados alterados sejam importados corretamente, excluindo os registros de nível superior que foram alterados desde a última importação e, em seguida, reimporte os registros modificados e qualquer coisa relacionada a eles. Isso me salvou de ter que escrever muitas exclusões complicadas que aparecem da parte inferior à parte superior do meu banco de dados.

Eu não considero as exclusões em cascata tão ruins quanto os gatilhos, pois elas apenas excluem dados; eles podem ter todos os tipos de coisas desagradáveis.

Em geral, evito completamente exclusões reais e uso exclusões lógicas (ou seja, ter uma coluna de bits chamada isDeleted que seja configurada como true).


2
Você me deixou curioso para aprender um pouco mais. Por que você prefere exclusões lógicas? Os dados com os quais você está trabalhando têm algo a ver com isso?
Tim Lovell-Smith

9

Um exemplo é quando você tem dependências entre entidades ... ou seja: Documento -> DocumentItems (quando você exclui Documento, DocumentItems não tem um motivo para existir)


5

Use a exclusão em cascata onde você deseja que o registro com o FK seja removido se o registro PK referente foi removido. Em outras palavras, onde o registro não faz sentido sem o registro de referência.

Acho a exclusão em cascata útil para garantir que as referências inativas sejam removidas por padrão, em vez de causar exceções nulas.


5

LIGAR Excluir cascata:

Quando você deseja que as linhas na tabela filho sejam excluídas Se a linha correspondente for excluída na tabela pai.

Se a exclusão em cascata não for usada, um erro será gerado para a integridade referencial .

Cascata de atualização ON:

Quando você deseja que a alteração na chave primária seja atualizada na chave estrangeira


5

Ouvi falar de DBAs e / ou "Política da Empresa" que proíbem o uso de "On Delete Cascade" (e outros) apenas por causa de más experiências no passado. Em um caso, um cara escreveu três gatilhos que acabaram se chamando. Três dias para recuperar resultaram em uma proibição total de gatilhos, tudo por causa das ações de um idjit.

É claro que às vezes são necessários gatilhos em vez de "Em exclusão em cascata", como quando alguns dados filhos precisam ser preservados. Mas em outros casos, é perfeitamente válido usar o método em cascata On Delete. Uma vantagem importante do "On Delete cascade" é que ele captura TODOS os filhos; um procedimento personalizado de ativação / armazenamento por escrito pode não funcionar se não estiver codificado corretamente.

Acredito que o desenvolvedor deve poder tomar a decisão com base no que é o desenvolvimento e no que as especificações dizem. Uma proibição de tapete baseada em uma experiência ruim não deve ser o critério; o processo de pensamento "Nunca use" é draconiano, na melhor das hipóteses. Uma chamada de julgamento precisa ser feita sempre e as alterações são feitas conforme o modelo de negócios muda.

Não é disso que se trata o desenvolvimento?


Não achei que fosse excluir tudo ... você quer dizer que o recurso realmente faz o que diz que faz? ...
Joel Coehoorn

3

Um motivo para colocar uma exclusão em cascata (em vez de fazê-lo no código) é melhorar o desempenho.

Caso 1: com uma exclusão em cascata

 DELETE FROM table WHERE SomeDate < 7 years ago;

Caso 2: sem exclusão em cascata

 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

Em segundo lugar, quando você adiciona uma tabela filho extra com uma exclusão em cascata, o código no Caso 1 continua funcionando.

Eu colocaria apenas uma cascata em que a semântica do relacionamento é "parte de". Caso contrário, algum idiota excluirá metade do seu banco de dados quando você fizer:

DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'

5
Sem saber qual base de dados você usa, sugiro que sua exclusão manual tenha um desempenho pior que a exclusão em cascata, porque não é definida com base. Na maioria dos bancos de dados, você pode excluir com base em uma associação a outra tabela e, portanto, ter uma exclusão muito mais rápida e baseada em conjuntos do que percorrer os registros.
HLGEM 10/11/08

2

Tento evitar exclusões ou atualizações que não solicitei explicitamente no SQL Server.

Em cascata ou pelo uso de gatilhos. Eles tendem a morder sua bunda por algum tempo, ao tentar rastrear um bug ou ao diagnosticar problemas de desempenho.

Onde eu os usaria é garantir consistência por pouco esforço. Para obter o mesmo efeito, você precisaria usar procedimentos armazenados.


2

Eu, como todo mundo aqui, acho que as exclusões em cascata são realmente apenas um pouco úteis (não é muito trabalhoso excluir dados referenciados em outras tabelas - se houver muitas tabelas, você simplesmente automatiza isso com um script), mas é realmente irritante quando alguém acidentalmente exclui em cascata alguns dados importantes que são difíceis de restaurar.

O único caso em que eu usaria é se os dados na tabela forem altamente controlados (por exemplo, permissões limitadas) e apenas atualizados ou excluídos de um processo controlado (como uma atualização de software) que foi verificado.


1

Uma exclusão ou atualização para S que remove um valor de chave estrangeira encontrado em algumas tuplas de R pode ser manipulada de uma de três maneiras:

  1. Rejeição
  2. Propagação
  3. anulação.

A propagação é conhecida como cascata.

Existem dois casos:

‣ Se uma tupla em S foi excluída, exclua as tuplas R que se referem a ela.

‣ Se uma tupla em S foi atualizada, atualize o valor nas tuplas R que se referem a ela.


0

Se você estiver trabalhando em um sistema com muitos módulos diferentes em versões diferentes, pode ser muito útil se os itens excluídos em cascata fizerem parte / pertencem ao detentor do PK. Caso contrário, todos os módulos exigiriam correções imediatas para limpar seus itens dependentes antes de excluir o proprietário da PK, ou a relação de chave estrangeira seria completamente omitida, possivelmente deixando toneladas de lixo no sistema se a limpeza não for executada corretamente.

Acabei de introduzir a exclusão em cascata para uma nova tabela de interseção entre duas tabelas já existentes (a interseção para excluir apenas), depois que a exclusão em cascata foi desencorajada por algum tempo. Também não é tão ruim se os dados são perdidos.

No entanto, é uma coisa ruim nas tabelas de lista do tipo enum: alguém exclui a entrada 13 - amarela da tabela "cores" e todos os itens amarelos no banco de dados são excluídos. Além disso, eles às vezes são atualizados de uma maneira excluir tudo inserir, levando a integridade referencial totalmente omitida. É claro que está errado, mas como você mudará um software complexo que está em execução há muitos anos, com a introdução da verdadeira integridade referencial correndo o risco de efeitos colaterais inesperados?

Outro problema é quando os valores originais da chave estrangeira devem ser mantidos mesmo após a exclusão da chave primária. Pode-se criar uma coluna de marca para exclusão e uma opção ON DELETE SET NULL para o FK original, mas isso novamente requer gatilhos ou código específico para manter o valor da chave redundante (exceto após a exclusão da PK).


0

As exclusões em cascata são extremamente úteis ao implementar entidades lógicas de super-tipo e subtipo em um banco de dados físico.

Quando são usadas tabelas separadas de supertipo e subtipo para implementar fisicamente os supertipos / subtipos (em vez de acumular todos os atributos de subtipo em uma única tabela física de supertipo), existe uma tabela Um relacionamento entre essas tabelas e o problema passa a ser como manter as chaves primárias 100% sincronizadas entre essas tabelas.

As exclusões em cascata podem ser uma ferramenta muito útil para:

1) Verifique se a exclusão de um registro de supertipo também exclui o registro de subtipo único correspondente.

2) Verifique se qualquer exclusão de um subtipo de registro também exclui o registro de supertipo. Isso é alcançado implementando um gatilho de exclusão "em vez de" na tabela de subtipo que exclui o registro de supertipo correspondente, que, por sua vez, em cascata exclui o registro de subtipo.

O uso de exclusões em cascata dessa maneira garante que nunca existam registros de super-tipo ou subtipo órfãos, independentemente de você excluir primeiro o registro de super-tipo ou o primeiro subtipo.


Bom exemplo. Na JPA, é a tabela ingressada na InheritanceStrategy. Para 1): Normalmente, você está usando uma estrutura de camada de persistência (EclipseLink, Hibernate, ...), que implementa a sequência excluída de uma entidade unida para excluir primeiro a parte unida e depois a super parte. Mas se você tiver um software mais básico, como um trabalho de importação ou arquivamento, é conveniente poder excluir a entidade apenas, excluindo a super parte. Em relação a 2): concordo, mas nesse caso o cliente já deve estar ciente de que está trabalhando em uma parte / junção da entidade.
Leo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.