1. 问题测试
开发人员反映应用程序中一条简单的delete语句执行报“超时已过时”错误。delete语句形式以下:spa
delete * from table_1 where id=@value3d
2. 分析blog
1)验证delete检索字段是否有索引索引
首先我想到的是检索字段 id 列上是否有索引,便是否能很快找到这条待删除的语句。开发
查看表的索引列表后,发现id上是存在索引的,并且是汇集索引。it
单独执行 select * from table_1 where id=@value 走的是汇集索引查找,速度是很是快的table
因此不是由于检索字段缺失索引致使的select
2)验证是否存在阻塞引用
接下来猜想是否是发生了阻塞,即delete语句等待其余会话释放KEY上的锁以得到X锁来执行删除
使用sys.sysprocesses查询当前delete会话状态,发现并未阻塞
3)查看delete语句的预估执行计划
前两步验证完毕后,愈加以为有点无从下手的感受。抛下本身所谓的经验,先看下delete语句执行计划吧
由于语句执行超时,不能查看真正的执行计划,因此查看估计的执行计划来分析问题。
以在AdventureWorks2012测试删除为例
执行delete from Person.Person where BusinessEntityID=6,执行计划部分截图为:
3. 结论
从执行计划中,发现了问题缘由:
删除数据的表被其余表所引用,SQLServer在删除被引用表数据时,会检查引用表是否存在引用值记录,以保证数据的参照完整性。
而目前引用表在外键字段上没有索引,致使使用索引扫描来查找,而且引用表记录数在百万以上,致使删除超时
4. 处理
在引用表的外键字段上增长非汇集索引
5. 思考
1)应用程序的物理删除数据是否合理及必须呢?是否能够经过增长删除标记或者单据状态之类,来实现逻辑删除呢?
2)引用表中字段的外键是否必须创建呢?看了一些应用系统,如用友、金蝶的系统,表中的外键字段不多。外键字段过多对插入删除的速度会有必定的影响。
3)若是创建了外键约束的话,引用表的外键字段和被引用表的主键字段应该最好要创建索引
若有不对的地方,欢迎拍砖,谢谢!O(∩_∩)O