从 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 引用。” 这些是否也有级联?如果没有,您最好删除CONSTRAINT
s、INSERT
ing 要保留到新表中的数据(具有相同的定义)、DROP
ing 现有表、重命名新表以及然后重新创建CONSTRAINT
s。如果他们这样做了,那么您要删除的不仅仅是 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 中的大表中删除大部分数据的策略的主要内容,如果未能解决你的问题,请参考以下文章