目前数据库中存在一张几千万行的日志表,按照数据保留策略仅需要保留最近一个月的数据,因此需要对历史数据进行清理。测试了几种方案最后选择了通过临时表来进行关联删除
1、在数据表上创建索引
1
  | 
CREATE INDEX IDX_ID ON dbo.Log(ID);
  | 
 
2、创建临时表并创建索引
1
2
3
4
5
  | 
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
CREATE TABLE #tmp(
ID bigint not null
);
CREATE CLUSTERED INDEX idx_temp_id on #tmp(ID);
  | 
 
3、将要删除的记录ID填充到临时表中
1
  | 
Insert into #tmp(id) select id from dbo.Log  WHERE [Date] < DATEADD(MONTH, -1, GETDATE())
  | 
 
4、关联进行删除
1
  | 
delete a from dbo.Log a ,#tmp b where a.id=b.id
  | 
 
经过测试4分钟删除了150w行记录,但问题在于该方式会造成阻塞,因此可以改写为下列方式,降低锁持有的时间
1
2
3
4
5
6
7
  | 
while 1=1
begin
     delete top(10000) A from dbo.Log  A,#apitmp b where a.id=b.id;
     --此处不能写任何语句,否则可能导致rowcount计数异常
     IF (@@rowcount<10000) BREAK;
end
GO
  | 
 
这样每次只删除10000行,当最后一次删除数量不到10000行则退出循环
思考题: 表中存在自增值,是否可以通过查询最近一个月中最小的ID,限制删除范围,然后根据ID构建分区,分批删除呢?类似于ORACLE中通过ROWID批量做DELETE的方式