Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

O SQL Server DRI (ON DELETE CASCADE) está lento?


SQL Server é melhor em operações baseadas em conjuntos, enquanto CASCADE exclusões são, por sua natureza, baseadas em registros.

SQL Server , ao contrário dos outros servidores, tenta otimizar as operações baseadas em conjuntos imediatos, porém, funciona apenas em um nível de profundidade. Ele precisa ter os registros excluídos nas tabelas de nível superior para excluir aqueles nas tabelas de nível inferior.

Em outras palavras, as operações em cascata funcionam de cima para baixo, enquanto sua solução funciona de baixo para cima, o que é mais baseado em set e eficiente.

Aqui está um esquema de amostra:
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

e seu plano:
  |--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)

Primeiro, SQL Server exclui registros de t_g , em seguida, une os registros excluídos com t_p e deleções deste último, finalmente, junta registros deletados de t_p com t_c e exclui de t_c .

Uma única junção de três tabelas seria muito mais eficiente nesse caso, e é isso que você faz com sua solução alternativa.

Se isso faz você se sentir melhor, Oracle não otimiza as operações em cascata de forma alguma:elas são sempre NESTED LOOPS e Deus te ajude se você esqueceu de criar um índice na coluna de referência.