起因是如此简单的一句sql
DELETE FROM tablename WHERE timekey=20150416
提示:Timeout 时间已到。在操作完成之前超时时间已过或服务器未响应。
提供几种解决思路:
1、检查WHERE条件中字段是否已建索引
2、检查是否被其他表引用,引用表外键字段上是否已建索引
3、分批次删除,根据容量大小设置条数
4、重建索引
第3点,稍微展开一下:
写法1:
首先我们能想到的分批肯定是 TOP
DELETE TOP(5000) FROM tablename WHERE timekey=20150416
top多少合适呢,具体还要根据实际场景自己试。
条数多了会造成锁阻塞,即使条数少了也不是没有阻塞可能的,而且听说频繁的删除操作会造成相同语句的IO差距很大,比较不稳定,没有亲自试,不知道传闻是不是真的。
*注:DELETE TOP(10) PERCENT 还有介样按百分比删除的写法,性能也不是很好。
执行结果:
执行计划:
写法2:
在有自增列且自增列有索引的情况下,分两步走,①取一批次ID,②删除
DELETE FROM tablename WHERE ID IN (54321,54322,54323......5000个ID...)
执行结果:
执行计划:
写法3:
在有自增列且自增列有索引的情况下,根据MIN(ID),MAX(ID)区间分批次删除。
DELETE FROM tablename
WHERE
ID>=MIN(ID)+5000
and ID<MIN(ID)+10000
and ID<=MAX(ID)
and timekey=20150416
当然,最好是将MIN(ID),MAX(ID)先读出来啦,我这里只是示意一下。
执行结果:
执行计划:
结论:
写法3在各方面都更为优质。当然这个结论是基于我的表约3000w条数据,每批5000条删除的情况,不排除其他场景下的会得到其他结论的可能。没有万能的语句,大家还是要自己试的啊。
提醒自己:
1、select min 和 max id 的时候记得写 with(nolock)啊啊啊
2、删除间隙记得 WAITFOR DELAY '0:0:1' 给其他程序一个时间啊啊啊啊啊啊