Mysql
 sql >> Database >  >> RDS >> Mysql

Vincoli di chiave esterna:quando utilizzare ON UPDATE e ON DELETE

Non esitate a porre vincoli al database. Sarai sicuro di avere un database coerente e questo è uno dei buoni motivi per utilizzare un database. Soprattutto se hai più applicazioni che lo richiedono (o una sola applicazione ma con una modalità diretta e una modalità batch che utilizza sorgenti diverse).

Con MySQL non hai vincoli avanzati come avresti in PostgreSQL, ma almeno i vincoli di chiave esterna sono piuttosto avanzati.

Prendiamo un esempio, una tabella azienda con una tabella utente contenente persone di questa azienda

CREATE TABLE COMPANY (
     company_id INT NOT NULL,
     company_name VARCHAR(50),
     PRIMARY KEY (company_id)
) ENGINE=INNODB;

CREATE TABLE USER (
     user_id INT, 
     user_name VARCHAR(50), 
     company_id INT,
     INDEX company_id_idx (company_id),
     FOREIGN KEY (company_id) REFERENCES COMPANY (company_id) ON...
) ENGINE=INNODB;

Diamo un'occhiata al IN AGGIORNAMENTO clausola:

  • SUL LIMITAZIONE DI AGGIORNAMENTO :l'impostazione predefinita :se provi ad aggiornare un company_id nella tabella COMPANY il motore rifiuterà l'operazione se almeno un UTENTE si collega a questa azienda.
  • IN AGGIORNAMENTO NESSUNA AZIONE :come RESTRICT.
  • IN AGGIORNAMENTO A CASCATA :di solito il migliore :se aggiorni un company_id in una riga della tabella COMPANY il motore lo aggiornerà di conseguenza su tutte le righe USER che fanno riferimento a questa COMPANY (ma nessun trigger attivato sulla tabella USER, avviso). Il motore terrà traccia delle modifiche per te, va bene.
  • IN AGGIORNAMENTO IMPOSTA NULLA :se aggiorni un company_id in una riga della tabella COMPANY il motore imposterà gli USER correlati company_id su NULL (dovrebbe essere disponibile nel campo USER company_id). Non riesco a vedere nulla di interessante da fare con questo in un aggiornamento, ma potrei sbagliarmi.

E ora su ON DELETE lato:

  • SU LIMITAZIONE ELIMINA :l'impostazione predefinita :se provi a eliminare un company_id Id nella tabella COMPANY il motore rifiuterà l'operazione se almeno un UTENTE si collega a questa azienda, può salvarti la vita.
  • SU CANCELLAZIONE NESSUNA AZIONE :come RESTRICT
  • SU ELIMINA CASCATA :pericoloso :se elimini una riga aziendale nella tabella AZIENDA il motore cancellerà anche i relativi UTENTI. Questo è pericoloso, ma può essere utilizzato per effettuare pulizie automatiche su tabelle secondarie (quindi può essere qualcosa che vuoi, ma sicuramente non per un'AZIENDA<->esempio UTENTE)
  • SU CANCELLAZIONE IMPOSTA NULLA :manciata :se elimini una riga AZIENDA i relativi UTENTI avranno automaticamente la relazione NULL. Se Null è il tuo valore per gli utenti senza azienda, questo può essere un buon comportamento, ad esempio potresti dover mantenere gli utenti nella tua applicazione, come autori di alcuni contenuti, ma rimuovere l'azienda non è un problema per te.

di solito il mio valore predefinito è:ON DELETE RESTRICT ON UPDATE CASCADE . con alcuni ON DELETE CASCADE per le tabelle delle tracce (log--non tutti i log--, cose del genere) e ON DELETE SET NULL quando la tabella master è un 'attributo semplice' per la tabella contenente la chiave esterna, come una tabella JOB per la tabella USER.

Modifica

È passato molto tempo da quando l'ho scritto. Ora penso che dovrei aggiungere un avvertimento importante. MySQL ha una grande limitazione documentata con le cascate. Le cascate non attivano attivatori . Quindi, se eri abbastanza sicuro di quel motore da usare i trigger, dovresti evitare i vincoli a cascata.

==> Vedi sotto l'ultima modifica, le cose si stanno muovendo su questo dominio

E non credo che questo verrà risolto un giorno. I vincoli di chiave esterna sono gestiti dall'archivio InnoDb e i trigger sono gestiti dal motore SQL di MySQL. Entrambi sono separati. Innodb è l'unico storage con la gestione dei vincoli, forse un giorno aggiungeranno trigger direttamente nel motore di storage, forse no.

Ma ho la mia opinione su quale elemento dovresti scegliere tra la scarsa implementazione del trigger e l'utile supporto per i vincoli delle chiavi esterne. E una volta che ti sarai abituato alla coerenza del database, adorerai PostgreSQL.

12/2017-Aggiornamento di questa modifica su MySQL:

come affermato da @IstiaqueAhmed nei commenti, la situazione è cambiata su questo argomento. Quindi segui il link e controlla la reale situazione aggiornata (che potrebbe cambiare ancora in futuro).