从 SQL Server 中的大表中删除大部分数据的策略

Posted

技术标签:

【中文标题】从 SQL Server 中的大表中删除大部分数据的策略【英文标题】:Strategies to delete most of the data from large table in SQL Server 【发布时间】:2021-07-22 16:20:50 【问题描述】:

我需要删除 90% 的表格。

我正在循环执行此语句(以保持事务较小)

DELETE TOP(1000) 
FROM Events 
WHERE EventID IN (SELECT EventId FROM EventsToDelete)  

两个表都有大约 5000 万行。

此语句的查询计划是两次索引扫描,这并不快。我可以采用哪些策略来加快整个过程?

其他表有对该表的 FK 引用。

【问题讨论】:

“其他表有对该表的 FK 引用。” 这些是否也有级联?如果没有,您最好删除CONSTRAINTs、INSERTing 要保留到新表中的数据(具有相同的定义)、DROPing 现有表、重命名新表以及然后重新创建CONSTRAINTs。如果他们这样做了,那么您要删除的不仅仅是 45M~ 行,而是相关表中的所有行;这很可能需要一些时间。 我认为这可行,但我不喜欢放弃约束,因为这假设我知道所有约束并且我希望代码能够工作,即使设置了新的约束......我猜没有别的办法? 您可以创建一个新表并从源表中插入 10%。然后删除源表。 @SteveC 即使有约束? 删除约束并在之后重新创建它们。你可能会发现这个答案很有用***.com/questions/66427736/…,它解释了如何快速切换数据。 【参考方案1】:

尝试将您的 IN() 重铸为 JOIN。

DELETE TOP(1000) e
  FROM Events e
  JOIN EventsToDelete d ON e.EventId = d.EventId;

这可能会优化 EventId 匹配。

这是一个更复杂但绝对更快的方案。在一个循环中,这样做:

CREATE TABLE #ids AS 
SELECT TOP(5000) EventId FROM EventsToDelete;
DELETE e
  FROM Events e
  JOIN #ids d ON e.EventId = d.EventId;
DELETE  e
  FROM EventsToDelete e
  JOIN #ids d ON e.EventId = d.EventId;
DROP TABLE #ids;

我在使用这种临时表策略逐渐细化 EventsToDelete 列表的大规模清除方面取得了很好的成功。

在您的操作之前使用

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

避免潜在的死锁。

而且,您可能可以使用 5k 或 10k 的批量大小,这样可以减少批量。

最后,查看 SSMS 中的实际执行计划,看看它是否推荐了您没有的索引。

【讨论】:

在加入 DELETE 语句之前,我会在 #ids 上添加一个唯一索引;否则我完全同意这是最快的方法恕我直言。 (我假设EventsToDelete 上已经有一个唯一(聚集?)索引,这意味着您也可以使用 ORDER BY 执行 TOP(5000),而无需任何额外费用,以确保您要删除的 id 很好地组合在一起)

以上是关于从 SQL Server 中的大表中删除大部分数据的策略的主要内容,如果未能解决你的问题,请参考以下文章

从具有 NULL 列的大表中删除重复项,这也需要考虑

从mysql中的大表中快速选择随机行

从mysql中的大表中快速选择随机行

如何在 SQL Server 中更新具有数百万行的大表?

在 BigQuery 中的大表中取消透视日期列

当从 id 从 30000 开始计时超过 2 分钟的大表中更新和选择时