关于sql server:使用T-SQL有效删除记录而不使用IN子句

Deleting records with T-SQL efficiently without using IN clause

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

1
2
3
4
5
6
-- 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"。

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

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

我很感激你的回答仍然是"不,不可能"。

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


使用NOT EXISTS

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


由于可读性原因,我更喜欢CTE,它也可以更改为使用SELECT来查看我要删除的内容。这种NOT EXISTS也可能更有效:

1
2
3
4
5
6
7
8
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到表的附加联接,因为只选择了一个表。


在另一种想法中,使用内部联接,因此只删除匹配项:

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

这很管用…

1
2
3
4
5
DELETE IH
    FROM IndexHistory IH
    Left JOIN IndexedLineItems LI
      ON IH.Docid = LI.DocId
    WHERE LI.DocId is Null