备注:因为实在无法在自己电脑上还原出此类情况,以下例子使用了工作时的截图
前几天上班的时候,同事遇到一个问题,cpu cost会少的一句sql,竟然返回很慢。
两列都有独自的普通索引,但是在执行计划里多出了个BITMAP CONVERSION FROM ROWIDS的过程。
参考了惜分飞的博客后,他的解释如下:
其目的是:.oracle将btree索引中获得的rowid信息通过BITMAP CONVERSION FROM ROWIDS的步骤转换成bitmap进行匹配,然后匹配完成后通过BITMAP CONVERSION TO ROWIDS再转换出rowid获得数据或者回表获得数据。
这种想象出现的原因为:oracle的cbo是根据cost来决定大小来选择合适的执行计划,当它计算获得通过bitmap的方式执行的时候cost会更小,它就会选择使用这样的执行计划。
一般出现这样的情况,都是因为对表建立的不适当的index导致,特别是对表中的唯一度不高的列建立了index,然后oracle就有可能选择两个这样的列转为为bitmap来执行。根据oracle的执行计划,肯定是cost最小的,但是它很多时候忽略了一致性读等其他条件,导致这个执行计划并非像oracle想象的那样最优,因为把btree index转为为bitmap index执行,需要消耗更多的cpu,特别是在cpu比较紧张的系统中,所以这样的情况如果发生在oltp系统中,一般都需要解决。
本例的解决办法是删除唯一度低的index,建立组合index。
以上用了他文章中的原话,不过在本例中启用了老外的建议,将参数 _b_tree_bitmap_plans设置为了false
alter session "_b_tree_bitmap_plans"=false;
可以看到当该参数设置为false后,不会出现将索引转换成位图的情况了。
不过可以发现,转换成位图索引的情况下cpu的消耗并不高,所以我对以上蓝色下划线字体的论述产生了质疑。
借鉴itpub上的一篇帖子,了解到当转换成位图索引时,cpu消耗会减低,但是会造成大量物理读(因为要将所有的索引读出,形成位图)。但是不转换时相反,cpu消耗会增高,物理读数量不高。
这又是一个典型的io和cpu之间的博弈了。本例中,cpu资源相对充裕,而io资源相对紧张,查询优化器使用了一个cost最小的执行计划,导致了比原来更慢。
本例中修改了隐藏参数解决问题,但是实际情况下,并不建议修改隐藏参数,这个会对系统造成隐患。比较好的解决方案是对于组合索引进行测试,在决定接下去的方式。
以下是隐藏参数 _b_tree_bitmap_plans的解释:使用B树索引的位图计划(该核心思想是数据库引擎能基于B树索引扫描返回的结果构建存在内存中的位图索引)
参考资料:
http://www.xifenfei.com/1531.html