【问题标题】:Deleting records with T-SQL efficiently without using IN clause在不使用 IN 子句的情况下使用 T-SQL 有效删除记录
【发布时间】:2019-03-14 10:48:56
【问题描述】:

在以下场景中,是否有一种有效的方法可以在不使用关键字IN 的情况下从 SQL Server 中删除记录:

-- If Documents were deleted, remove them from your ocean
DELETE FROM IndexHistory 
WHERE DocId IN (SELECT IH.Docid 
                FROM IndexHistory IH 
                LEFT JOIN IndexedLineItems I ON IH.Docid = I.DocId
                WHERE I.Docid IS NULL)

如果你研究这个场景,你在括号内有你想要从查询中删除的所有记录。

已记录的事实是使用“IN”是低效的。所以有人会认为应该有一种方法可以在不使用“IN”的情况下删除这些记录,因为您的所有记录都可以在不使用“IN”的情况下识别。

例如,我认为这样的事情可能是可能的,但我没有正确的语法:

DELETE FROM IndexHistory IH 
LEFT JOIN IndexedLineItems I ON IH.Docid = I.DocId
WHERE I.Docid IS NULL

我很感激答案可能仍然是“不,这不可能。”

如果不可能,也许可以建议为 Microsoft 改进语言。在我这样做之前,我想我会在这里发帖看看我是否遗漏了什么。

【问题讨论】:

  • 你不是这个意思吗:stackoverflow.com/questions/16481379/…
  • 马克,不完全是,但它是相关的并且是一个很好的发现,并且有助于我发布一个额外的可能答案(我的不是内连接,而是左连接)。底部的一些答案似乎也不错。

标签: sql-server tsql syntax subquery


【解决方案1】:

使用not exists:

Delete ih from IndexHistory ih
    where not exists (select 1 from IndexedLineItems ili where ih.Docid = ili.DocId)

【讨论】:

  • 你错过了加入还是什么?
  • @Kam 不,这是一个相关的子查询。加入是ih.Docid = ili.DocId
  • 仅供参考,具有相关子查询的“不存在”效果更好的原因是它可以利用索引作为直接将外部表连接到内部表。使用“in”子句,优化器无法对将要操作的结果做出假设,因此必须对其进行扫描。事实证明这是一个很大的好处。
  • 我收到了这个错误。消息 102,级别 15,状态 1,第 2 行 'ih' 附近的语法不正确。
  • @Kam。 . .那是一个错字。 . .我省略了别名。
【解决方案2】:

出于可读性原因,我更喜欢 CTE,也可以将其更改为使用 SELECT 来查看我要删除的内容。这个NOT EXISTS 也可能更高效:

WITH DeleteData AS
(
  SELECT IH.Docid 
  FROM IndexHistory IH 
  WHERE NOT EXISTS( SELECT 1 FROM IndexedLineItems I
                    WHERE I.DocId = IH.DocId)
)
DELETE FROM DeleteData

您不需要从此 CTE 到表的额外 JOIN,因为只选择了一个表。

【讨论】:

  • 这似乎奏效了。我以前从未见过这个(有...)。我会暂时保持开放状态,以防有其他答案。
  • @Kam:这是common-table-expression。无论 CTE 本身有多复杂,您都可以随时写 SELECT * FROM DeleteData 来查看您将删除的内容。然后在 CTE 中添加更多列(或简单地 SELECT IH.* ...)也可能很有用。不必只选择Docid。
【解决方案3】:

换一种思路,改用内连接,这样你只删除匹配项:

DELETE FROM IndexHistory IH 
JOIN IndexedLineItems I ON IH.Docid = I.DocId
WHERE I.Docid IS NOT NULL

【讨论】:

    【解决方案4】:

    这很好用...

    DELETE IH
        FROM IndexHistory IH
        Left JOIN IndexedLineItems LI
          ON IH.Docid = LI.DocId
        WHERE LI.DocId is Null
    

    【讨论】:

    • 这里有很多很棒的答案和大量的好信息。但这是最直接的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多