Buona spiegazione del comportamento in cascata (ON DELETE / UPDATE)


98

Non progetto schemi ogni giorno, ma quando lo faccio, provo a configurare correttamente gli aggiornamenti / eliminazioni in cascata per semplificare l'amministrazione. Capisco come funzionano le cascate, ma non riesco mai a ricordare quale tavolo sia quale.

Ad esempio, se ho due tabelle - Parente Child- con una chiave esterna su Childquei riferimenti Parente ha ON DELETE CASCADE, quali record attivano una cascata e quali record vengono eliminati dalla cascata? La mia prima ipotesi sarebbe che i Childrecord vengano eliminati quando i Parentrecord vengono eliminati, poiché i Childrecord dipendono dai Parentrecord, ma ON DELETEè ambiguo; potrebbe significare eliminare il Parentrecord quando il Childrecord viene eliminato, oppure potrebbe significare eliminare il Childrecord quando Parentviene eliminato. Quindi che cos'è?

Vorrei che la sintassi era ON PARENT DELETE, CASCADE, ON FOREIGN DELETE, CASCADEo qualcosa di simile per rimuovere l'ambiguità. Qualcuno ha qualche mnemonica per ricordare questo?

Risposte:


138

Se vi piacciono le Parente Childtermini e ti senti sono facili da ricordare, come si può la traduzione di ON DELETE CASCADEaLeave No Orphans!

Ciò significa che quando una Parentriga viene eliminata (uccisa), nessuna riga orfana dovrebbe rimanere attiva nella Childtabella. Anche tutti i figli della riga padre vengono uccisi (eliminati). Se uno di questi figli ha nipoti (in un'altra tabella tramite un'altra chiave esterna) e viene ON DELETE CASCADEdefinito, anche questi dovrebbero essere uccisi (e tutti i discendenti, purché sia ​​definito un effetto a cascata).

Il FOREIGN KEYvincolo stesso potrebbe anche essere descritto come Allow No Orphans!(in primo luogo). Non Childdovrebbe mai essere permesso (scritto) nella tabella figlio se non ha una Parent(una riga nella tabella padre).

Per coerenza, è ON DELETE RESTRICTpossibile tradurre in (meno aggressivo) You Can't Kill Parents!È possibile eliminare (eliminare ) solo le righe senza figli.


3
Sento che manca ancora qualcosa nell'analogia. Un bambino non può avere più di un genitore? In questo caso, uccidere un genitore renderà il bambino orfano?
Jus12,

7
@ Jus12 No, i vincoli di chiave esterna funzionano solo con 1 genitore. Non è una buona analogia riguardo a questo aspetto.
ypercubeᵀᴹ

1
@ypercube: non è permesso? Order(custID, itemID, orderID)dove si custIDriferisce a una chiave primaria nella Customerstabella e si itemIDriferisce a una chiave primaria nella Itemstabella. Non Orderavrai due genitori?
Jus12,

4
@ Jus12 Ovviamente è consentito ma sarebbero 2 vincoli di chiave esterna. Quindi ogni bambino (ordine) avrebbe un genitore (cliente) e un genitore (articolo). Tuttavia, i comportamenti dei 2 FK potrebbero differire. (Ad esempio, potrebbe essere che uccidere i clienti ucciderebbe tutti i loro (ordini) figli, ma uccidere oggetti non ucciderebbe i loro ordini.)
ypercubeᵀᴹ

1
L'analogia con i genitori può ancora funzionare se non diciamo "orfano". Se ci sono due riferimenti a due genitori separati in una voce figlio, questo può ancora essere visto come figlio di una coppia divorziata. Limita: "Non ti lascerò uccidere mia madre" Cascade: "Se uccidi mio padre, morirò anche io"
Christopher McGowan,

31

Ad esempio, se ho due tabelle - Parent e Child - in cui i record Child sono di proprietà dei record Parent, quale tabella necessita di ON DELETE CASCADE?

ON DELETE CASCADE è una clausola facoltativa in una dichiarazione di chiave esterna. Lo stesso vale per la dichiarazione di chiave esterna. (Significato, nella tabella "figlio".)

... potrebbe significare eliminare il record Parent quando il record Child viene eliminato, oppure potrebbe significare eliminare il record Child quando il Parent viene eliminato. Quindi che cos'è?

Un modo per interpretare una dichiarazione di chiave esterna è "Tutti i valori validi per questa colonna provengono da" that_column "in" that_table "." Quando elimini una riga nella tabella "figlio", a nessuno importa. Non influisce sull'integrità dei dati.

Quando si elimina una riga dalla tabella "parent" - da "that_table" - si rimuove un valore valido dai valori possibili per la tabella "child". Per mantenere l'integrità dei dati, devi fare qualcosa per la tabella "figlio". Le eliminazioni a cascata sono una cosa che puoi fare.


2

SQL: 2011 Spec

Esistono cinque opzioni per ON DELETEe ON UPDATEche possono essere applicate a FOREIGN KEY. Questi vengono chiamati <referential actions>, direttamente dalle specifiche SQL: 2011

  • ON DELETE CASCADE: se viene eliminata una riga della tabella di riferimento, vengono eliminate tutte le righe corrispondenti nella tabella di riferimento.
  • ON DELETE SET NULL: se viene eliminata una riga della tabella di riferimento, tutte le colonne di riferimento in tutte le righe corrispondenti della tabella di riferimento devono essere impostate su null.
  • ON DELETE SET DEFAULT: se viene eliminata una riga della tabella di riferimento, tutte le colonne di riferimento in tutte le righe corrispondenti della tabella di riferimento devono essere impostate sul valore predefinito della colonna.
  • ON DELETE RESTRICT: è vietato eliminare una riga della tabella referenziata se quella riga ha righe corrispondenti nella tabella referenziata.
  • ON DELETE NO ACTION (impostazione predefinita) : non esiste un'azione di eliminazione referenziale; il vincolo referenziale specifica solo un controllo del vincolo.

La chiave esterna stabilisce la relazione dipendente. Il <referential action>determina cosa accade quando il rapporto è disciolto.

Esempio / Metafora / Spiegazione

Per questo esempio, accetteremo il modello comune di società ed economia: dove ognuno businessè un'azienda che mantiene una relazione con la bourgeoisiea fatcat_owner.

CREATE TABLE bourgeoisie(
  fatcat_owner varchar(100) PRIMARY KEY
);
INSERT INTO bourgeoisie(fatcat_owner) VALUES
  ( 'Koch Brothers' );

CREATE TABLE business (
  name         varchar(100),
  fatcat_owner varchar(100) REFERENCES bourgeoisie
);
INSERT INTO business(name, fatcat_owner)
  VALUES ('Georgia-Pacific', 'Koch Brothers');

Se tutti gli businesses sono direttamente influenzati dal bourgeoisieloro, fatcat_ownerallora cosa fai dopo la rivoluzione dei lavoratori quando spegni la fatcat_owners e hai una società senza classi?

-- Viva la revolución 
BEGIN;
  DELETE FROM bourgeoisie;
END;

Hai alcune opzioni qui,

  • Ferma la rivoluzione. In SQL gergo, RESTRICT. Alcune persone credono che questo sia il male minore, ma di solito si sbagliano.
  • Lascialo andare avanti. In tal caso, quando si verifica la rivoluzione, SQL ti offre quattro opzioni,

    • SET NULL- lascialo vuoto. Chissà, forse il capitalismo viene ripristinato bourgeoisie, e gli oligarchi riempiono il ruolo del fatcat_owners. Nota importante, la colonna deve essere NULLABLE(non NOT NULL) o questo non può mai accadere.
    • SET DEFAULT- forse hai avuto un DEFAULTche ha gestito questo? A DEFAULTpuò chiamare una funzione. Forse il tuo schema è già pronto per la rivoluzione.
    • CASCADE- non esiste alcun controllo dei danni. Se bourgeoisieva bene, anche il business. Se un'azienda deve avere un fatcat_pig, allora a volte ha più senso perdere i dati piuttosto che avere una non-attività in una businesstabella.
    • NO ACTION- questo è essenzialmente un metodo per ritardare il controllo, in MySQL non è diverso da RESTRICT, ma in PostgreSQL, saresti in grado di fare

      -- Not a real revolution.
      -- requires constraint be DEFERRABLE INITIALLY DEFERRED
      BEGIN;
        SET CONSTRAINTS ALL DEFERRED;
        DELETE FROM bourgeoisie;
        INSERT INTO bourgeoisie VALUES ( 'Putin' );
        UPDATE business SET fatcat_pig = 'Putin';
      END;
      

      In tale sistema, il vincolo viene convalidato solo prima del commit della transazione. Ciò può comportare l'arresto della rivoluzione, ma è possibile ripristinare la transazione, per un certo grado di "recupero".


Fa referencedtavolo significa tabella padre e referencingtabella significa tabella figlio?
sg552,

@ sg552 Sì, l'hai capito correttamente.
informatik01

1

Sarebbe un semplice mnemonico

ON DELETE della CASCADE principale [eliminando] qui

Questo ti dice quali eliminazioni (eliminazioni del genitore) vengono messe in cascata, dove va l'istruzione ON DELETE CASCADE (sul figlio) e cosa viene cancellato (il figlio).


-3

bene, forse possiamo razionalizzare la sintassi. Facciamo un esempio di Python:

class Parent(self):
    # define parent's fields

class Child(self):    
    # define child's fields
    parent_pk_is_childs_foreign_key = models.ForeignKey(Parent, on_delete=models.CASCADE)

ciò che dice questa riga è on_delete del Parent (che è accennato per caso nell'istruzione), per favore elimina la cancellazione sul figlio. Questo è il motivo per cui l'istruzione CASCADE è definita a livello di figlio, segna quei figli che devono essere eliminati

Ad esempio se hai avuto un'altra lezione

class GrownUpChild(self):    
        # define grown up child's fields
        parent_pk_is_childs_foreign_key = models.ForeignKey(Parent, on_delete=models.DO_NOTHING)

questa struttura mostrerebbe chiaramente quale dei bambini deve essere rimosso (Child) e quali devono rimanere (GrownUpChild) anche se orfani

[Modifica: dato il contesto della discussione, in particolare nei casi di on_delete = models.CASCADE ecc.], In effetti è spesso un comportamento desiderato lasciare i figli di un genitore cancellato, a causa di motivi di auditing e di segnalazione, nonché di recupero accidentale eliminazioni. [ovviamente il software di livello aziendale sarà costruito attorno a tale comportamento e contrassegnerà i record eliminati come cancellati = 1 invece di eliminarli effettivamente e inoltre non li includerà in alcuna query per il front-end, meno alcuni report appositamente progettati. Inoltre avrà la funzione di eliminare i record == 1 cancellati dal database, che di solito saranno eseguiti dall'amministratore dell'interfaccia utente, spesso evitando qualsiasi coinvolgimento da parte dell'amministratore del database.]


1
"In effetti, è spesso un comportamento desiderato lasciare i figli di un genitore cancellato, a causa di motivi di auditing e segnalazione, nonché di recupero di cancellazioni accidentali" - sarebbe disastroso in un database (sano).
dezso

@dezso grazie per il tuo contributo. Tuttavia, più sistemi CRM di livello aziendale fanno esattamente questo.
George Mogilevsky,

TBH che non lo rende più sensato. Una volta ho ricevuto un incarico per sistemare la merda derivante da un simile approccio - nessuna gioia, tranne la busta paga.
dezso

sembri un esperto amministratore di database :) Posso sentire perfettamente il tuo punto. Il software che ho menzionato sopra lo fa, in realtà ha una funzione per rimuovere quelli cancellati = 1 manualmente, quindi spetta all'amministratore dell'app effettuare questa chiamata. Normalmente l'amministratore del database non è nemmeno coinvolto nel mantenimento di questo aspetto. E inoltre, l'intera classe di database del software è costruita attorno al concetto, quindi controlla sempre la presenza di flag eliminati nelle operazioni crud
George Mogilevsky,

Sì, questo è un modello noto e sano, ma allora dovresti eventualmente cambiare la dicitura sopra per riflettere questo.
dezso
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.