sql - 使用过滤器 WHERE Field IN (<empty set>) 时从大表中删除花费的时间太长

标签 sql sql-server

我有一个不太明白的特殊问题。有一个大表,我们称之为 LT,带有主键 ID。我有一个 DELETE 语句来删除重复项,如下所示:

DELETE FROM LT
WHERE ID IN ( 
    SELECT l.ID FROM ( 
        SELECT Field1, Field2, COUNT(*) as total, MIN(ID) LowestID FROM LT (NOLOCK) WHERE Field1 = @fieldOneParam 
        GROUP BY Field1, Field2
        HAVING COUNT(*) > 1 
    ) a 
    INNER JOIN LT l (NOLOCK) on l.Field1 = a.Field1 And l.Field2 = a.Field2 And l.ID > a.LowestID 
)

不,如果嵌套选择中有结果,则查询运行得相对较快。但是,当这个子查询时:

SELECT l.ID FROM ( 
    SELECT Field1, Field2, COUNT(*) as total, MIN(ID) LowestID FROM LT (NOLOCK) WHERE Field1 = @fieldOneParam 
    GROUP BY Field1, Field2
    HAVING COUNT(*) > 1 
) a 
INNER JOIN LT l (NOLOCK) on l.Field1 = a.Field1 And l.Field2 = a.Field2 And l.ID > a.LowestID 

返回一个空集,整个语句永远运行。我检查了估计的执行计划,它充满了表假脱机、嵌套循环和查找表具有的每个索引(很多)。不是针对子查询,而是针对删除本身。

为什么要这么做?难道它不应该只使用 ID 字段(它有)的聚集索引吗?由于 IN (...) 子句的集合为空,查询不应该在几秒钟内运行吗?

谢谢。

最佳答案

这并不能回答您的问题,但这里有另一种方法可以删除重复项,同时使用 common table expression 保留每个 Field1、Field2 的最低 idrow_number() :

;with cte as (
  select *
    , rn = row_number() over (
        partition by t.Field1, t.Field2 
        order by t.Id
      )
  from lt as t
)
--delete 
select * -- preview
from cte
where rn > 1;

原始查询中的 NOLOCK 提示可能会导致您出现问题。

关于sql - 使用过滤器 WHERE Field IN (<empty set>) 时从大表中删除花费的时间太长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46855217/

相关文章:

mysql - 如何在 MySQL 触发器中访问 "INSERTED"值?

java - 将intellij idea连接到sql server数据库

sql - SSMS - ISO 镜像的下载链接在哪里?

sql-server - 根据表数据隐藏 ssrs 文本框

java - JPA 和 MS SQL GenerationType.Identity 始终为 null

mysql - From 在此位置无效,应为 : ';' in mysql

php - 表实际上不存在,但从该表查询返回数据

mysql - INSERT INTO `tab1` SELECT `tab2` 当 `tab2` 没有记录时输入空值

sql - 如何获取特定员工的所有进出时间?

java - JDBC:如何在准备好的语句中执行功能?