Domanda

Quando si configurano chiavi esterne in SQL Server, in quali circostanze dovresti averle a cascata in caso di eliminazione o aggiornamento e qual è il ragionamento alla base?

Questo probabilmente vale anche per altri database.

Cerco soprattutto esempi concreti di ogni scenario, preferibilmente da qualcuno che li ha utilizzati con successo.

È stato utile?

Soluzione

Riepilogo di ciò che ho visto finora:

  • Ad alcune persone non piace affatto il cascata.

Eliminazione a cascata

  • Cascade Delete può avere senso quando la semantica della relazione può comportare un'esclusiva "è parte di"descrizione.Ad esempio, un record OrderLine fa parte del suo ordine principale e OrderLine non verrà mai condiviso tra più ordini.Se l'Ordine dovesse svanire, anche OrderLine dovrebbe svanire, e una riga senza Order sarebbe un problema.
  • L'esempio canonico di Cascade Delete è SomeObject e SomeObjectItems, dove non ha alcun senso che un record di elementi esista senza un record principale corrispondente.
  • Dovresti non utilizza Cascade Elimina se stai preservando la cronologia o utilizzando una "eliminazione graduale/logica" in cui imposti solo una colonna di bit eliminata su 1/true.

Aggiornamento a cascata

  • Cascade Update può avere senso quando si utilizza una chiave reale anziché una chiave surrogata (colonna identità/incremento automatico) tra le tabelle.
  • L'esempio canonico di Cascade Update è quando si dispone di una chiave esterna modificabile, come un nome utente che può essere modificato.
  • Dovresti non utilizzare Cascade Update con chiavi che sono colonne Identità/incremento automatico.
  • Cascade Update viene utilizzato al meglio insieme a un vincolo univoco.

Quando utilizzare la cascata

  • Potresti voler ottenere una conferma extra forte dall'utente prima di consentire l'esecuzione a cascata di un'operazione, ma dipende dalla tua applicazione.
  • Il collegamento a cascata può metterti nei guai se imposti le chiavi esterne in modo errato.Ma dovresti stare bene se lo fai bene.
  • Non è saggio usare il collegamento a cascata prima di averlo compreso a fondo.Tuttavia, è una funzionalità utile e quindi vale la pena dedicare del tempo a comprenderla.

Altri suggerimenti

Le chiavi esterne sono il modo migliore per garantire l'integrità referenziale di un database.Evitare le cascate dovute alla magia è come scrivere tutto in assembly perché non ti fidi della magia dietro i compilatori.

Ciò che è negativo è l’uso sbagliato delle chiavi esterne, come ad esempio crearle al contrario.

L'esempio di Juan Manuel è l'esempio canonico, se usi il codice ci sono molte più possibilità di lasciare DocumentItem spuri nel database che verranno e ti morderanno.

Gli aggiornamenti a cascata sono utili, ad esempio, quando si hanno riferimenti ai dati tramite qualcosa che può cambiare, ad esempio una chiave primaria di una tabella utenti è la combinazione nome, cognome.Quindi vuoi che le modifiche in quella combinazione si propaghino ovunque venga fatto riferimento.

@Aidan, quella chiarezza a cui fai riferimento ha un costo elevato, la possibilità di lasciare dati spuri nel tuo database, il che è non piccolo.Per me, di solito è solo la mancanza di familiarità con il DB e l'incapacità di scoprire quali FK sono in atto prima di lavorare con il DB che alimentano quella paura.O quello, o il costante uso improprio della cascata, usandola dove le entità non erano concettualmente correlate o dove devi preservare la storia.

Non utilizzo mai le eliminazioni a cascata.

Se voglio che qualcosa venga rimosso dal database, voglio dire esplicitamente al database cosa voglio eliminare.

Naturalmente sono una funzione disponibile nel database e potrebbero esserci momenti in cui è giusto utilizzarle, ad esempio se hai una tabella "order" e una tabella "orderItem" potresti voler cancellare gli elementi quando elimini un ordine.

Mi piace la chiarezza che ottengo dal farlo in codice (o procedura memorizzata) piuttosto che in modo "magico".

Per lo stesso motivo anch'io non sono un fan dei trigger.

Qualcosa da notare è che se elimini un "ordine" riceverai il rapporto "1 riga interessata" anche se l'eliminazione a cascata ha rimosso 50 "orderItem".

Lavoro molto con le eliminazioni a cascata.

È bello sapere che chiunque lavori contro il database non lascerà mai dati indesiderati.Se le dipendenze crescono, cambio semplicemente i vincoli nel diagramma in Management Studio e non devo modificare sp o dataacces.

Detto questo, ho 1 problema con le eliminazioni a cascata e questi sono riferimenti circolari.Ciò spesso porta a parti del database che non presentano eliminazioni a catena.

Lavoro molto sui database e raramente trovo utili le eliminazioni a cascata.L'unica volta che li ho utilizzati in modo efficace è stato in un database di reporting aggiornato da un lavoro notturno.Mi assicuro che tutti i dati modificati vengano importati correttamente eliminando tutti i record di livello superiore che sono cambiati dall'ultima importazione, quindi reimporto i record modificati e tutto ciò che è correlato ad essi.Mi evita di dover scrivere un sacco di cancellazioni complicate che guardano dal basso verso l'alto del mio database.

Non considero le eliminazioni a cascata tanto dannose quanto i trigger poiché eliminano solo i dati, i trigger possono contenere tutti i tipi di cose brutte all'interno.

In generale evito del tutto le eliminazioni reali e utilizzo le eliminazioni logiche (ad es.avere invece una colonna di bit chiamata isDeleted che viene impostata su true).

Un esempio è quando hai dipendenze tra entità...cioè:Documento -> DocumentItems (quando elimini Document, DocumentItems non hanno motivo di esistere)

Utilizza l'eliminazione a cascata nel punto in cui desideri che il record con l'FK venga rimosso se il relativo record PK di riferimento è stato rimosso.In altre parole, dove il record non ha senso senza il record di riferimento.

Trovo utile l'eliminazione a cascata per garantire che i riferimenti morti vengano rimossi per impostazione predefinita anziché causare eccezioni nulle.

ON Elimina cascata:

Quando vuoi righe nella tabella figlio da eliminare Se la riga corrispondente viene eliminata nella tabella padre.

Se sull'eliminazione a cascata non viene utilizzato, verrà generato un errore per integrità referenziale.

ON Aggiornamento a cascata:

Quando vuoi modifica della chiave primaria in cui essere aggiornato chiave esterna

Uno dei motivi per inserire un'eliminazione a cascata (invece di farlo nel codice) è migliorare le prestazioni.

Caso 1:Con un'eliminazione a cascata

 DELETE FROM table WHERE SomeDate < 7 years ago;

Caso 2:Senza eliminazione a 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

In secondo luogo, quando aggiungi una tabella figlio aggiuntiva con un'eliminazione a cascata, il codice nel caso 1 continua a funzionare.

Io inserirei solo una cascata in cui la semantica della relazione è "parte di".Altrimenti qualche idiota cancellerà metà del tuo database quando fai:

DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'

Ho sentito parlare di DBA e/o "Politica aziendale" che proibiscono l'uso di "On Delete Cascade" (e altri) semplicemente a causa di brutte esperienze in passato.In un caso un ragazzo ha scritto tre trigger che hanno finito per chiamarsi a vicenda.Tre giorni per recuperare hanno portato al divieto totale dei trigger, tutto a causa delle azioni di un idjit.

Naturalmente a volte sono necessari Trigger invece di "On Delete cascade", come quando è necessario preservare alcuni dati figlio.Ma in altri casi, è perfettamente valido utilizzare il metodo a cascata On Elimina.Un vantaggio chiave di "On Delete cascade" è che cattura TUTTI i bambini;una procedura di trigger/memorizzazione scritta personalizzata potrebbe non essere codificata correttamente.

Credo che allo sviluppatore dovrebbe essere consentito di prendere una decisione in base allo sviluppo e a ciò che dicono le specifiche.Un divieto di moquette basato su una brutta esperienza non dovrebbe essere il criterio;il processo di pensiero "Non usare mai" è nella migliore delle ipotesi draconiano.Ogni volta è necessario effettuare un giudizio e apportare modifiche man mano che il modello di business cambia.

Non è questo lo sviluppo?

Cerco di evitare eliminazioni o aggiornamenti che non ho richiesto esplicitamente nel server SQL.

O tramite cascata o tramite l'uso di trigger.Tendono a prenderti a calci in culo prima o poi, sia quando cerchi di rintracciare un bug sia quando diagnostichi problemi di prestazioni.

Li utilizzerei per garantire coerenza con uno sforzo minimo.Per ottenere lo stesso effetto dovresti utilizzare le procedure memorizzate.

Io, come tutti gli altri qui, trovo che le eliminazioni a cascata siano in realtà solo marginalmente utili (in realtà non è molto lavoro eliminare i dati di riferimento in altre tabelle - se ci sono molte tabelle, puoi semplicemente automatizzarlo con uno script) ma davvero fastidioso quando qualcuno elimina accidentalmente a cascata alcuni dati importanti che sono difficili da ripristinare.

L'unico caso in cui lo utilizzerei è se i dati nella tabella table sono altamente controllati (ad esempio, autorizzazioni limitate) e aggiornati o eliminati solo tramite un processo controllato (come un aggiornamento software) che è stato verificato.

Una cancellazione o un aggiornamento di S che rimuove un valore di chiave esterna trovato in alcune tuple di R può essere gestito in tre modi:

  1. Rifiuto
  2. Propagazione
  3. annullamento.

La propagazione viene detta a cascata.

Ci sono due casi:

‣ Se una tupla in S è stata cancellata, cancella le tuple R che si riferivano ad essa.

‣ Se una tupla in S è stata aggiornata, aggiorna il valore nelle tuple R che si riferiscono ad essa.

Se stai lavorando su un sistema con molti moduli diversi in versioni diverse, può essere molto utile che gli elementi eliminati a cascata facciano parte/possedano del titolare della PK.Altrimenti, tutti i moduli richiederebbero patch immediate per ripulire gli elementi dipendenti prima di eliminare il proprietario della PK, oppure la relazione con la chiave esterna verrebbe omessa completamente, lasciando probabilmente tonnellate di spazzatura nel sistema se la pulizia non viene eseguita correttamente.

Ho appena introdotto l'eliminazione a cascata per una nuova tabella di intersezione tra due tabelle già esistenti (solo l'intersezione da eliminare), dopo che l'eliminazione a cascata era stata scoraggiata per un bel po' di tempo.Inoltre, non è poi così male se i dati vengono persi.

Tuttavia, è una cosa negativa sulle tabelle elenco simili a enum:qualcuno cancella la voce 13 - giallo dalla tabella "colori" e tutti gli elementi gialli nel database vengono cancellati.Inoltre, questi a volte vengono aggiornati in un modo cancella tutto, inserisci tutto, portando alla totale omissione dell'integrità referenziale.Naturalmente è sbagliato, ma come si cambierà un software complesso che funziona da molti anni, con l'introduzione di una vera integrità referenziale che rischia di avere effetti collaterali inattesi?

Un altro problema è quando i valori originali della chiave esterna devono essere mantenuti anche dopo che la chiave primaria è stata eliminata.È possibile creare una colonna contrassegnata per la rimozione definitiva e un'opzione ON DELETE SET NULL per l'FK originale, ma anche questo richiede trigger o codice specifico per mantenere il valore della chiave ridondante (tranne dopo l'eliminazione del PK).

Le eliminazioni a cascata sono estremamente utili quando si implementano entità logiche di supertipo e sottotipo in un database fisico.

Quando vengono utilizzate tabelle separate di supertipi e sottotipi per implementare fisicamente supertipi/sottotipi (invece di raggruppare tutti gli attributi dei sottotipi in un'unica tabella fisica di supertipi), esiste una tabella uno-a -una relazione tra queste tabelle e il problema diventa quindi come mantenere le chiavi primarie sincronizzate al 100% tra queste tabelle.

Le eliminazioni a cascata possono essere uno strumento molto utile per:

1) Assicurarsi che l'eliminazione di un record di super-tipo cancelli anche il corrispondente record di singolo sottotipo.

2) Assicurarsi che qualsiasi eliminazione di un record di sottotipo elimini anche il record di supertipo.Ciò si ottiene implementando un trigger di eliminazione "invece di" sulla tabella dei sottotipi che va ed elimina il record del supertipo corrispondente, che, a sua volta, elimina a cascata il record del sottotipo.

L'utilizzo delle eliminazioni a catena in questo modo garantisce che non esista mai alcun record orfano di supertipo o sottotipo, indipendentemente dal fatto che si elimini prima il record del supertipo o prima il record del sottotipo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top