What is the problem with foreign key cascade multiple paths and cycles?

The reason we forbid using cascade delete has to do with performance and locking. Yes it's not so bad when you delete one record but sooner or later you will need to delete a large group of records and your database will comes to a standstill.

If you are deleting enough records, SQL Server might escalate to a table lock and no one can do anything with the table until it is finished.

We recently moved one of our clients to his own server. As part of the deal we also then had to delete all of that client's records form our original server. Deleting all his information in batches (so as not to cause problems with other users) took a couple of months. If we had cascade delete set up, the database would have been inaccessible to the other clients for a long time as millions of records were deleted in one transaction and hundreds of tables were locked until the transaction was done.

I could also see a scenario where a deadlock might have occured in using cascade delete because we have no control over the order the cascade path would have taken and our database is somewhat denormalized with clientid appearing in most tables. So if it locked the one table that had a foreign key also to a third table as well as the client table that was in a differnt path, it possibly couldn't check that table in order to delete from the third table because this is all one transaction and the locks wouldn't be released until it was done. So possibly it wouldn't have let us set up cascade deletes if it saw the possibility of creating deadlocks in the transaction.

Another reason to avoid cascading deletes is that sometimes the existence of a child record is reason enough not to delete the parent record. For instance, if you have a customer table and that customer has had orders in the past, you would not want to delete him and lose the information on the actual order.


Consider a table of employees:

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);

Now suppose Bill retires:

DELETE FROM Employees WHERE Name = "Bill";

Ooooppps; everyone just got sacked!

[We can debate whether the details of the syntax are correct; the concept stands, I think.]


You have a child table with 2 cascade paths from the same parent: one "delete", one "null".

What takes precedence? What do you expect afterwards? etc

Note: A trigger is code and can add some intelligence or conditions to a cascade.