troubleshooting many latch free(multiblock read objects) wait when index range scan

本案例来自东区某客户,数据库版本rac 11.2.0.4。有一条并发很高的sql,不定时的会产生大量的latch free,sql执行时间比正常时段有大概100倍的性能衰减。

由于客户业务比较特殊,sql分析的信息、awr都无法取出,这里只能用文字来描述。关键点如下:

  • 客户使用的优化器模式为RBO,所有的表和索引均无统计信息。
  • 首先分析latch free,可以通过P2关联v$latch.latch#来匹配具体是什么latch,通过排查看到的当时产生争用的具体latch为multiblock read objects。
  • 查看具体sql的执行计划发现执行计划中只有简单INDEX RANGE SCAN +TABLE ACCESS BY INDEX ROWID
  • 虽然使用的rbo,但是sql执行计划存在cost,说明仍然使用的CBO,原因是sql中使用了+index的hint

multiblock read objects顾名思义应该就是当对对象进行多块读请求的latch,但是执行计划并不涉及TFS和IFFS,都是单块读的操作,为何会请求这个latch呢?

思前想后只有2个可能性:

  • oracle的preread特性
  • 动态采样

关于oracle的preread特性在之前的文章有写过,这里就不描述了,基本可以排除这个原因,因为一个长期运行并未重启的系统,并且buffer cache基本没啥变化,preread基本是不会工作的。

案例:index range scan真的不会多块读吗?

那么很可能就是动态采样了,我们知道当使用rbo时是不会进行动态采样的。但是如果rbo的sql使用了hint其实就是使用CBO了,当表没有统计信息时,就会进行动态采样。这一点可以通过10046去确认。

如何确认是动态采样导致的呢?我采用了gdb+systemtap去跟踪函数的方式,虽然有点麻烦,但是我觉得唯有这样能非常明确的证明是否是这个问题导致的。(主要还是客户对技术比较执着,不然不太容易说服客户)

测试环境模拟以及进行测试的sql都与实际情况一致:

测试动态采样时:

当使用动态采样时,通过gdb或者short_stack可以观察到具体的函数调用

其中本案例相关的关键函数如下:

  • kslgetl:kernel service latching and post-wait get latch
  • kcbzibmlt :kernel cache buffers buffer handling input buffer (reads a block from disk into a buffer) for multiblock read
  • kcbzib :kernel cache buffers buffer handling input buffer (reads a block from disk into a buffer)
  • kcbgtcr :kernel cache buffers get consistent read

systemtap更加细致的观察到该sql执行过程中调用的所有函数:

手动释放掉刚才持有的latch之后重新执行sql,并开启systemtap跟踪。

systemtap脚本

运行stp脚本之后执行sql

systemtap输出:

systemtap可以看到通过kslgetl函数请求的latch地址为6001d768,正好就是multiblock read objects。

当sql级别禁用动态采样时:

flush buffer cache之后执行sql:

并未发现该latch的请求。所以解决方案就是再加一个hint DYNAMIC_SAMPLING(0)禁用该sql的动态采样。

 

此条目发表在Oracle, Oracle troubleshooting, Oralce performance分类目录,贴了, , 标签。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注