Domanda

In MSSQL 2005 ho appena colpito il famigerato messaggio di errore:

  

L'introduzione del vincolo FOREIGN KEY XXX sulla tabella YYY può causare cicli o percorsi multipli in cascata. Specificare ON DELETE NO AZIONE o ON UPDATE NO AZIONE o modificare altri vincoli ESTERI CHIAVE.

Ora StackOverflow ha diversi argomenti su questo messaggio di errore, quindi ho già la soluzione (nel mio caso dovrò usare i trigger), ma sono curioso di sapere perché c'è un problema del genere .

A quanto ho capito, ci sono fondamentalmente due scenari che vogliono evitare: un ciclo e percorsi multipli. Un ciclo sarebbe dove due tabelle hanno chiavi esterne in cascata tra loro. OK, un ciclo può comprendere anche diverse tabelle, ma questo è il caso di base e sarà più facile da analizzare.

I percorsi multipli sarebbero quando TableA ha chiavi esterne a TableB e TableC e anche TableB ha una chiave esterna su TableC. Ancora una volta: questo è il caso minimo di base.

Non riesco a vedere alcun problema che sorgerebbe quando un record verrebbe eliminato o aggiornato in una di quelle tabelle. Certo, potresti dover interrogare la stessa tabella più volte per vedere quali record devono essere aggiornati / eliminati, ma è davvero un problema? È un problema di prestazioni?

In altri argomenti SO le persone arrivano fino a etichettare usando cascades come " " rischioso; e dichiari che " la risoluzione dei percorsi a cascata è un problema complesso " ;. Perché? Dov'è il rischio? Dov'è il problema?

È stato utile?

Soluzione

Hai una tabella figlio con 2 percorsi in cascata dello stesso genitore: uno " elimina " ;, uno " null " ;.

Cosa ha la precedenza? Cosa ti aspetti dopo? etc

Nota: un trigger è un codice e può aggiungere alcune informazioni o condizioni a una cascata.

Altri suggerimenti

Il motivo per cui vietiamo l'uso dell'eliminazione in cascata ha a che fare con le prestazioni e il blocco. Sì, non è così male quando si elimina un record, ma prima o poi sarà necessario eliminare un grande gruppo di record e il database si arresterà.

Se si eliminano abbastanza record, SQL Server potrebbe passare a un blocco della tabella e nessuno può fare nulla con la tabella fino al termine.

Di recente abbiamo spostato uno dei nostri client sul suo server. Come parte dell'accordo abbiamo anche dovuto eliminare tutti i record di quel client dal nostro server originale. L'eliminazione di tutte le sue informazioni in batch (in modo da non causare problemi con altri utenti) ha richiesto un paio di mesi. Se avessimo impostato l'eliminazione a cascata, il database sarebbe stato inaccessibile agli altri client per lungo tempo poiché milioni di record sono stati eliminati in una transazione e centinaia di tabelle sono state bloccate fino al completamento della transazione.

Potrei anche vedere uno scenario in cui potrebbe essersi verificato un deadlock nell'uso dell'eliminazione in cascata perché non abbiamo alcun controllo sull'ordine che il percorso in cascata avrebbe preso e il nostro database è in qualche modo denormalizzato con clientid che appare nella maggior parte delle tabelle. Quindi, se bloccava una tabella che aveva una chiave esterna anche su una terza tabella e la tabella client che si trovava in un percorso diverso, probabilmente non poteva controllare quella tabella per eliminarla dalla terza tabella perché tutto qui una transazione e i blocchi non sarebbero stati rilasciati fino al completamento. Quindi forse non ci avrebbe permesso di impostare le eliminazioni in cascata se avesse visto la possibilità di creare deadlock nella transazione.

Un altro motivo per evitare l'eliminazione a cascata è che a volte l'esistenza di un record figlio è un motivo sufficiente per non eliminare il record principale. Ad esempio, se si dispone di una tabella clienti e quel cliente ha avuto ordini in passato, non si desidera eliminarlo e perdere le informazioni sull'ordine reale.

Considera una tabella di dipendenti:

CREATE TABLE Employee
(
    EmpID   INTEGER NOT NULL PRIMARY KEY,
    Name    VARCHAR(40) NOT NULL,
    MgrID   INTEGER NOT NULL REFERENCES Employee(EmpID) ON DELETE CASCADE
);

INSERT INTO Employees(     1, "Bill",   1);
INSERT INTO Employees(    23, "Steve",  1);
INSERT INTO Employees(234212, "Helen", 23);

Ora supponiamo che Bill si ritiri:

DELETE FROM Employees WHERE Name = "Bill";

Ooooppps; tutti sono stati appena licenziati!

[ Possiamo discutere se i dettagli della sintassi sono corretti; il concetto è valido, credo. ]

Penso che il problema sia che quando fai un percorso " ON ELIMINA CASCATA " e l'altro "ON DELETE RESTRICT", oppure "NO AZIONE". il risultato (il risultato) è imprevedibile. Dipende da quale trigger di eliminazione (anche questo è un trigger, ma quello che non devi costruire da solo) verrà eseguito per primo.

Concordo sul fatto che le cascate sono "rischiose" e dovrebbe essere evitato. (Personalmente preferisco mettere in cascata le modifiche manualmente piuttosto che avere un server sql che si occupi automaticamente di esse). Questo anche perché anche se il server sql cancellasse milioni di righe, l'output verrebbe comunque visualizzato come

(1 riga (e) interessate)

Penso che utilizzare un'opzione ON DELETE CASCADE sia una questione del modello di business che stai implementando. Una relazione tra due oggetti business potrebbe essere una semplice "associazione", in cui entrambe le estremità della relazione sono correlate, ma per il resto oggetti indipendenti il ??cui ciclo di vita sono diversi e controllati da un'altra logica. Vi sono, tuttavia, anche "aggregazione" relazioni, in cui un oggetto potrebbe effettivamente essere visto come il "genitore" o "proprietario" di un "figlio" o "dettaglio" oggetto. C'è la nozione ancora più forte di una "composizione". relazione, in cui un oggetto esiste esclusivamente come composizione di un numero di parti. Nell'associazione "quot" caso, di solito non dichiarerai un vincolo ON DELETE CASCADE. Per aggregazioni o composizioni, tuttavia, ON DELETE CASCADE consente di mappare il modello di business sul database in modo più accurato e dichiarativo. Questo è il motivo per cui mi dà fastidio che MS SQL Server limiti l'uso di questa opzione a un singolo percorso a cascata. Se non sbaglio, molti altri sistemi di database SQL ampiamente utilizzati non impongono tali restrizioni.

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