sql >> Database >  >> RDS >> Sqlserver

Is SQL Server DRI (ON DELETE CASCADE) traag?

SQL Server is het beste in set-gebaseerde bewerkingen, terwijl CASCADE verwijderingen zijn van nature gebaseerd op records.

SQL Server , in tegenstelling tot de andere servers, probeert de directe set-gebaseerde bewerkingen te optimaliseren, maar het werkt slechts één niveau diep. De records in de tabellen op het hoogste niveau moeten worden verwijderd om die in de tabellen op het lagere niveau te verwijderen.

Met andere woorden, trapsgewijze bewerkingen werken up-down, terwijl uw oplossing down-up werkt, wat meer set-based en efficiënter is.

Hier is een voorbeeldschema:

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)

, deze vraag:

DELETE
FROM    t_g
WHERE   id > 50000

en zijn 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)

Ten eerste, SQL Server verwijdert records van t_g , voegt zich vervolgens bij de verwijderde records met t_p en verwijdert uit de laatste, ten slotte voegt records samen die zijn verwijderd uit t_p met t_c en verwijdert uit t_c .

Een enkele join met drie tabellen zou in dit geval veel efficiënter zijn, en dit is wat u doet met uw tijdelijke oplossing.

Als je je er beter door voelt, Oracle optimaliseert op geen enkele manier cascadebewerkingen:het zijn altijd NESTED LOOPS en God helpe je als je bent vergeten een index te maken in de referentiekolom.




  1. Laravel - PDO Prepared Statement - Kan geen query's uitvoeren terwijl andere niet-gebufferde query's actief zijn

  2. Help a.u.b. voorkomen dat deze ODP.NET-code en transacties opnieuw worden opgebouwd in de gegevenslaag

  3. Voeg een procentteken toe aan een getal in MariaDB

  4. meerdere waarde opgeslagen in een enkele kolom in de MySQL-database?