DELETE查询非常慢

hwc*_*rwe 15 sql sql-server performance table-variable sql-execution-plan

我有SQL性能问题.出于突发原因,以下查询非常缓慢:

我有两个列表,其中包含某个表的Id.如果Id已存在于第二个列表中,我需要删除第一个列表中的所有记录:

DECLARE @IdList1 TABLE(Id INT)
DECLARE @IdList2 TABLE(Id INT)

-- Approach 1
DELETE list1
FROM @IdList1 list1
INNER JOIN @IdList2 list2 ON list1.Id = list2.Id

-- Approach 2
DELETE FROM @IdList1
WHERE Id IN (SELECT Id FROM @IdList2)
Run Code Online (Sandbox Code Playgroud)

这两个列表可能包含超过10,000条记录.在这种情况下,两个查询都需要超过20秒才能执行.

执行计划也显示了一些我不理解的东西.也许这就解释了为什么它如此缓慢: 查询两个查询

我用10,000个连续的整数填充了两个列表,因此两个列表都包含值1-10.000作为起始点.

正如您所看到的,两个查询显示@ IdList2 实际行数为50.005.000 !!.@ IdList1是正确的(实际行数是10.000)

我知道还有其他解决方案如何解决这个问题.就像填写从第一个列表中删除的第三个列表一样.但我的问题是:

为什么这些删除查询这么慢,为什么我会看到这些奇怪的查询计划?

Cha*_*ana 15

向表变量添加主键并观察它们的尖叫声

DECLARE @IdList1 TABLE(Id INT primary Key not null)
DECLARE @IdList2 TABLE(Id INT primary Key not null)
Run Code Online (Sandbox Code Playgroud)

因为这些表变量没有索引,所以任何连接或子查询必须检查10,000次10,000 = 100,000,000对值的顺序.

  • "任何连接或子查询必须按10,000次10,000 = 100,000,000对值的顺序进行检查." 这仅适用于嵌套循环.散列或合并连接将处理每个输入一次(虽然合并连接也需要排序) (2认同)
  • @martin,我已经有一段时间没有读过这些东西了,所以我忘记了规则,但是是否因为没有索引而选择了嵌套循环?要执行其他循环算法,是否不需要索引来对值进行排序?同样,没有索引,它仍然必须检查每对值-无论使用哪种循环算法来创建它们。-如您所注意到的,例外是合并联接,但是必须对它们进行预排序。 (2认同)
  • @CharlesBretana - 只要有一个equi连接,它就不能使用哈希或合并连接.合并连接将需要对两个输入进行排序(如同创建索引一样)但是一旦创建了索引,它显然可能更有用,因为它将使其他查询受益(所以+1) (2认同)

Mar*_*ith 12

SQL Server在表变量为空时编译计划,并且在添加行时不重新编译它.尝试

DELETE FROM @IdList1
WHERE Id IN (SELECT Id FROM @IdList2)
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)

这将考虑表变量中包含的实际行数并删除嵌套循环计划

当然,Id通过约束创建索引对于使用表变量的其他查询也可能是有益的.

  • @CharlesBretana - [我的答案在这里]有一些链接和示例代码(http://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable -in-SQL服务器) (2认同)