最近,有个比较大的项目出现数据库死锁。经过分析数据库trace文件,发现死锁的是基础数据表疾病诊断。根据对应的sql语句找到了问题所在,门诊医生录入诊断时,程序里面同时去更新疾病诊断基础表,造成诊断基础表被锁。
经过分析,诊断基础表共27886条记录,分布在312个数据块中,每个数据块包含75到114条不等的记录。由于数据库服务器安装的oracle rac, 共两个节点,oracle的最小单位是数据块,当几百个门诊大夫一起录入诊断的时候,频繁的更新基础数据,造成数据块不停的在两个节点之间转换,而且很多病人都同时患多种疾病,大夫录入诊断的顺序也很可能不同,造成疾病诊断表被锁。
另外从数据库trace文件中发现了itl锁,每个数据块上面的事务槽位上限是255,通过查询疾病诊断表,发现数据块里面最大的记录数也就才114行,而程序里面是按照值唯一的字段(无索引)去更新的记录,理论上应该不会出现itl锁,但是理论终归是理论,由于数据块里面数据插入之后的再更新,占用了一部分预留的10%的pctfree空间,造成了没有足够的可用空闲空间来支撑更多的事务并发,所以出现了itl锁,这些锁一起造成了部分大夫无法下诊断长达20分钟。
这种在并发量很高的业务流程里面去更新常用的基础表,可以说,从设计上就是错误的。如今的项目,数据量都已经达到了很高的程度了,而且并发也越来越大,性能问题应该引起所有IT人员的注意。数据量少或者并发量低的时候,一些性能低的sql语句可能发现不了问题,但是随着系统运行时间的增长,定会有出现问题的那一天。