sql >> Base de Datos >  >> RDS >> Sqlserver

¿Es lento SQL Server DRI (ON DELETE CASCADE)?

SQL Server es mejor en operaciones basadas en conjuntos, mientras que CASCADE las eliminaciones son, por su naturaleza, basadas en registros.

SQL Server , a diferencia de los otros servidores, intenta optimizar las operaciones inmediatas basadas en conjuntos, sin embargo, trabaja solo en un nivel de profundidad. Necesita eliminar los registros en las tablas de nivel superior para eliminar los de las tablas de nivel inferior.

En otras palabras, las operaciones en cascada funcionan de arriba hacia abajo, mientras que su solución funciona de abajo hacia arriba, lo que es más eficiente y basado en conjuntos.

Aquí hay un esquema de muestra:

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)

, esta consulta:

DELETE
FROM    t_g
WHERE   id > 50000

y su 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)

Primero, SQL Server elimina registros de t_g , luego une los registros eliminados con t_p y elimina de este último, finalmente, une los registros eliminados de t_p con t_c y borra de t_c .

En este caso, una única unión de tres tablas sería mucho más eficiente, y esto es lo que hará con su solución alternativa.

Si te hace sentir mejor, Oracle no optimiza las operaciones en cascada de ninguna manera:siempre son NESTED LOOPS y Dios te ayude si olvidaste crear un índice en la columna de referencia.