大规模删除数千万行是一个典型且极具风险的操作,尤其在高负载数据库中。历史上,许多人只是编写 DELETE FROM,这导致了表的锁定和事务日志的溢出。主要问题是:事务变得过于庞大,服务进程变得缓慢,而回滚的后果可能难以预测。
解决方案 — 实现“分批”删除,在循环中处理少量行,使用短期事务,以最小化锁定和对系统的影响:
示例代码(SQL Server):
WHILE 1=1 BEGIN DELETE TOP (10000) FROM YourHugeTable WHERE CreatedAt < DATEADD(year,-2,GETDATE()); IF @@ROWCOUNT = 0 BREAK; WAITFOR DELAY '00:00:01'; -- 小暂停以减少负载 END
关键特点:
如果使用 TRUNCATE 代替 DELETE,是否总是更快和更安全?
不。TRUNCATE 的确更快,但:
在大规模 DELETE 中,使用过滤字段的索引重要吗?
是的,适当的过滤列(例如 CreatedAt)索引可以加速删除行的查找并降低对表的负载。如果没有索引,请求将会影响整个表,即使每批删除数量不多。
CREATE INDEX idx_createdat ON YourHugeTable(CreatedAt);
同时执行多个线程的大规模 DELETE 会发生什么?
这会导致锁定竞争:将会引发锁定升级、等待时间增加以及死锁的可能性。大规模删除应通过一个进程进行,或者进行非常谨慎地分区操作。
DBA 决定一次性通过 DELETE FROM Log WHERE dt < '2021-01-01' 清空 6000 万行的表。服务器几乎“挂起”,其他进程开始等待,日志文件大幅增长,恢复变得漫长。
优点:
缺点:
将删除分成每批 10,000 行进行,流程得到控制,每批后有暂停。服务器运行稳定,其他任务正常执行,管理员监控进度。
优点:
缺点: