客户一套系统说下午3点到4点间跑批过慢,导致整个应用程序用起来很痛苦。
生了awr报告,发现逻辑读达到每秒30多万,top 5等待事件中enq: TX - allocate ITL entry一马当先。
顺势看了下top sql,发现一条update语句执行了1800多次,总执行时间超过了5000秒。
(比较痛苦啊,每次写这种故障总结,都没有详细图表信息粘贴,只能靠语言描述。。。)
基本可以推理出:
由于某张表上存在大量dml操作(update),导致ITL不够用,产生了争用。
这里补充下ITL知识:
ITL(Interested Transaction List)是Oracle数据块内部的一个组成部分,用来记录该块所有发生的事务,一个itl可以看作是一个记录,在一个时间,可以记录一个事务(包括提交或者未提交事务)。当然,如果这个事务已经提交,那么这个itl的位置就可以被反复使用了,因为itl类似记录,所以,有的时候也叫itl槽位。
如果一个事务一直没有提交,那么,这个事务将一直占用一个itl槽位,itl里面记录了事务信息,回滚段的入口,事务类型等等。
对于已经提交的事务,itl槽位最好不要马上被覆盖,因为一致性读可能会用到这个信息,一致性读的时候,可能需要从这里获得回滚段的入口,并从回滚段中获得一致性读。
itl的个数,受参数initrans控制,最大的itl个数,受maxtrans控制,在一个块内部,默认分配了2个或3个itl的个数,如果这个块内还有空闲空间,那么Oracle是可以利用这些空闲空间并再分配itl的。如果没有了空闲空间,那么,这个块因为不能分配新的itl,所以就可能发生itl等待。
如果在并发量特别大的系统中,最好分配足够的itl个数,其实它并浪费不了太多的空间,或者,设置足够的pctfree,保证itl能扩展,但是pctfree有可能是被行数据给消耗掉的,如update,所以,也有可能导致块内部的空间不够而导致itl等待。
解决方法就是将表,和用到的索引的initrans的值改大一点:
alter table table_name initrans 20;
alter index index_name rebuild initrans 20 online;