SQL Server
eignet sich am besten für satzbasierte Operationen, während CASCADE
Löschungen sind naturgemäß datensatzbasiert.
SQL Server
versucht im Gegensatz zu den anderen Servern, die unmittelbaren satzbasierten Operationen zu optimieren, funktioniert jedoch nur eine Ebene tief. Es müssen die Datensätze in den Tabellen der oberen Ebene gelöscht werden, um die Datensätze in den Tabellen der unteren Ebene zu löschen.
Mit anderen Worten, kaskadierende Operationen arbeiten von oben nach unten, während Ihre Lösung von unten nach oben arbeitet, was satzbasierter und effizienter ist.
Hier ist ein Beispielschema:
CREATE TABLE t_g (id INT NOT NULL PRIMARY KEY)
CREATE TABLE t_p (id INT NOT NULL PRIMARY KEY, g INT NOT NULL, CONSTRAINT fk_p_g FOREIGN KEY (g) REFERENCES t_g ON DELETE CASCADE)
CREATE TABLE t_c (id INT NOT NULL PRIMARY KEY, p INT NOT NULL, CONSTRAINT fk_c_p FOREIGN KEY (p) REFERENCES t_p ON DELETE CASCADE)
CREATE INDEX ix_p_g ON t_p (g)
CREATE INDEX ix_c_p ON t_c (p)
, diese Abfrage:
DELETE
FROM t_g
WHERE id > 50000
und sein Plan:
|--Sequence
|--Table Spool
| |--Clustered Index Delete(OBJECT:([test].[dbo].[t_g].[PK__t_g__176E4C6B]), WHERE:([test].[dbo].[t_g].[id] > (50000)))
|--Index Delete(OBJECT:([test].[dbo].[t_p].[ix_p_g]) WITH ORDERED PREFETCH)
| |--Sort(ORDER BY:([test].[dbo].[t_p].[g] ASC, [test].[dbo].[t_p].[id] ASC))
| |--Table Spool
| |--Clustered Index Delete(OBJECT:([test].[dbo].[t_p].[PK__t_p__195694DD]) WITH ORDERED PREFETCH)
| |--Sort(ORDER BY:([test].[dbo].[t_p].[id] ASC))
| |--Merge Join(Inner Join, MERGE:([test].[dbo].[t_g].[id])=([test].[dbo].[t_p].[g]), RESIDUAL:([test].[dbo].[t_p].[g]=[test].[dbo].[t_g].[id]))
| |--Table Spool
| |--Index Scan(OBJECT:([test].[dbo].[t_p].[ix_p_g]), ORDERED FORWARD)
|--Index Delete(OBJECT:([test].[dbo].[t_c].[ix_c_p]) WITH ORDERED PREFETCH)
|--Sort(ORDER BY:([test].[dbo].[t_c].[p] ASC, [test].[dbo].[t_c].[id] ASC))
|--Clustered Index Delete(OBJECT:([test].[dbo].[t_c].[PK__t_c__1C330188]) WITH ORDERED PREFETCH)
|--Table Spool
|--Sort(ORDER BY:([test].[dbo].[t_c].[id] ASC))
|--Hash Match(Inner Join, HASH:([test].[dbo].[t_p].[id])=([test].[dbo].[t_c].[p]))
|--Table Spool
|--Index Scan(OBJECT:([test].[dbo].[t_c].[ix_c_p]), ORDERED FORWARD)
Zuerst SQL Server
löscht Datensätze aus t_g
, fügt dann die gelöschten Datensätze mit t_p
hinzu und löscht aus letzterem, verbindet schließlich Datensätze, die aus t_p
gelöscht wurden mit t_c
und löscht aus t_c
.
Ein einzelner Drei-Tabellen-Join wäre in diesem Fall viel effizienter, und genau das machen Sie mit Ihrer Problemumgehung.
Wenn Sie sich dadurch besser fühlen, Oracle
optimiert in keiner Weise Kaskadenoperationen:Sie sind immer NESTED LOOPS
und Gott helfe Ihnen, wenn Sie vergessen haben, einen Index für die Referenzierungsspalte zu erstellen.