【问题标题】:Strategies to delete most of the data from large table in SQL Server从 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 即使有约束?
  • 删除约束并在之后重新创建它们。你可能会发现这个答案很有用stackoverflow.com/questions/66427736/…,它解释了如何快速切换数据。

标签: sql-server query-optimization


【解决方案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 很好地组合在一起)
猜你喜欢
  • 2023-02-16
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
相关资源
最近更新 更多