【问题标题】:Why DELETE TOP(X) statement is not deleting the same records that a previous SELECT TOP(X) returned?为什么 DELETE TOP(X) 语句没有删除先前 SELECT TOP(X) 返回的相同记录?
【发布时间】:2019-03-12 02:41:40
【问题描述】:

正如标题所说,我一直在运行此命令以从表中删除一些记录,但我注意到如果我之前运行查询选择 TOP(X) 记录,它并没有删除列出的相同记录。

DELETE 命令不应该遵循与SELECT 相同的默认顺序吗?如果不是,为什么?

我不知道这是否重要,但这是我正在运行的删除命令:

DELETE TOP (100000) t
FROM Ticket AS t
    LEFT JOIN Series s on t.SeriesId = s.id
    LEFT JOIN Payment p on t.id = p.TicketId
WHERE s.EndDate <= DATEADD(MONTH, -1, GETDATE()) AND t.ExportDate is null AND p.TicketId is null

对于选择,只需将第一行替换为SELECT TOP(100000) t.*

【问题讨论】:

  • 不。没有“默认排序”。如果您未指定ORDER BY,则任何订购都是有效的。指定删除顺序的方法是将选择放入具有确定性order by 的 CTE,然后从 CTE 中删除
  • 表中的记录以优化其存储和检索的方式存储到磁盘。而已。它不关心记录的顺序,除非您指定 ORDER BY 子句。
  • 为什么是LEFT JOIN Series s?无论如何,WHERE s.EndDate 使其成为内部连接
  • 规则一:如果您要使用“TOP”,请始终使用“ORDER BY”。总是。

标签: sql-server


【解决方案1】:

如果没有 ORDER BY,数据的顺序无法得到保证。

【讨论】:

  • 希望你不介意那个编辑。我发现它们对过去的许多人非常有用。
  • @scsimon 当然不是;任何使答案更有用的东西总是受欢迎的
【解决方案2】:

不。没有“默认排序”。如果您未指定ORDER BY,则任何订购都是有效的。

生成的顺序将取决于执行计划,甚至可能在给定的执行计划中不稳定(例如,并行性可能会将行分配给不同的线程,具体分布取决于每个调度程序当时的繁忙程度)

此外,即使忽略 ORDER BY 问题,TOP 的语义对于 SELECTDELETE 也是不同的。如果Series 中有多个匹配给定的Ticket(并匹配EndDate),则SELECT 将计算连接的行,而DELETE 将在删除之前将它们折叠为1,并仅计算从Ticket 删除的行。

要以确定性方式执行DELETE,您可以首先构造一个对此有效的SELECT 语句(将所有连接替换为EXISTS/NON EXISTS),然后您可以将其放入CTE 并从中删除。

WITH CTE
     AS (SELECT TOP (100000) t.*
         FROM   Ticket AS t
         WHERE  t.ExportDate IS NULL
                AND EXISTS (SELECT *
                            FROM   Series s
                            WHERE  t.SeriesId = s.id
                                   AND s.EndDate <= DATEADD(MONTH, -1, GETDATE()))
                AND NOT EXISTS(SELECT *
                               FROM   Payment p
                               WHERE  t.id = p.TicketId)
         ORDER  BY t.id)
DELETE FROM CTE 

【讨论】:

  • 我问这个的唯一原因是因为我收到的SELECT TOP(X) 的结果完全相同,无论我运行多少次。
  • 这将取决于执行计划。如果您获得了非并行执行计划并且没有正在进行的数据修改会移动行或导致统计信息更新并且计划发生更改,那么是的,这很可能会发生,但您不应该依赖您的任何订单观察该语句的复制,更不用说在不同的上下文中使用它了,比如将 SELECT 更改为 DELETE
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 2022-11-30
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多