ORACLE 10g CBO的问题
第一个问题是bind peeking,很容易造成执行计划不稳定,SQL的执行计划可能会突然会变得很差,造成系统瞬间LOAD很高。
第二个问题是recost for order by,oracle往往会过高的估计排序的成本,从而忽略了索引的选择性,而选择一个避免排序的执行计划,通常这个执行计划都很差。
今天又碰到了这个问题,差点造成故障。由于应用的某个功能,需要对一个时间列gmt_create创建索引,当索引创建后(创建时带着compute statistics参数),一条sql的执行计划就发生了改变:
select * from
(select * from table where member_id=:1 order by member_id,gmt_create desc) where rownum<=100
oracle为了避免排序忽略了member_id上的索引,反而使用gmt_create时间列上的索引,走full index scan来避免排序。
我尝试对索引和列进行分析,都无法使这个sql走到正确的执行计划上,最终只好将这个索引删除。
相比较而言,9i的数据库几乎没有出现过这样的问题,应该是10g在CBO的计算上做了很多改变。
oracle提供了隐含参数,通过设置隐含参数_optim_peek_user_binds=FALSE,可以关掉bind peeking功能。
另外一个隐含参数,_sort_elimination_cost_ratio,描述是:cost ratio for sort eimination under first_rows mode.将这个参数修改为1,降低ORACLE计算order by的成本。这个参数默认是0。看解释有点恐怖:A value of 0 would mean that an execution plan with ORDER BY sort elimination be chosen even if it is more expensive than queries that do a final sorting.不知道ORACLE怎么想的,这个解释表明ORACLE认为排序的成本非常大,只要有机会都会尽量避免排序。
对于我们这种在线系统来说,一旦执行计划走错,系统不会给你太多时间作调整和尝试,负载通常在几秒钟就飙升到100以上,如果不迅速处理,系统很快就会宕掉。可能ORACLE也意识了这个问题,11g提供了Invisible Indexes和SQL Plan Management的特性,这样DBA在尝试做调整时,就算出现问题,我们也可以控制数据库,并有机会作尝试和调整,这对于OLTP系统来说,太重要了。
–EOF–