Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

SQL Server DRI (ON DELETE CASCADE) est-il lent ?

SQL Server est le meilleur pour les opérations basées sur des ensembles, tandis que CASCADE les suppressions sont, de par leur nature, basées sur des enregistrements.

SQL Server , contrairement aux autres serveurs, essaie d'optimiser les opérations basées sur les ensembles immédiats, cependant, il ne fonctionne qu'à un niveau de profondeur. Il doit supprimer les enregistrements des tables de niveau supérieur pour supprimer ceux des tables de niveau inférieur.

En d'autres termes, les opérations en cascade fonctionnent de haut en bas, tandis que votre solution fonctionne de bas en haut, ce qui est plus efficace et basé sur des ensembles.

Voici un exemple de schéma :

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)

, cette requête :

DELETE
FROM    t_g
WHERE   id > 50000

et son 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)

Tout d'abord, SQL Server supprime les enregistrements de t_g , puis joint les enregistrements supprimés avec t_p et supprime de ce dernier, enfin, joint les enregistrements supprimés de t_p avec t_c et supprime de t_c .

Une seule jointure de trois tables serait beaucoup plus efficace dans ce cas, et c'est ce que vous faites avec votre solution de contournement.

Si cela vous aide à vous sentir mieux, Oracle n'optimise en aucune façon les opérations en cascade :ce sont toujours des NESTED LOOPS et Dieu vous aide si vous avez oublié de créer un index sur la colonne de référencement.