某客户说一个库迁移完系统慢,看top的话,free是0,但是buff\cache都挺多的,实际上这个对oracle影响不大,在非生产,可以用echo 3 > /proc/sys/vm/drop_caches 这个生产不要用,后果未知,注意看/proc/meminfo 也要注意大页的问题,meminfo里很多信息,对应可以去调整
后来排除内存问题的不是别的,正是在看完awr后在老环境和旧环境执行同一sql发现执行计划、逻辑读、执行时间都相差很大导致性能出现整体的问题,首先这个有问题的执行计划如下:
SQL_ID 3zay3d3hq52cu, child number 0
2 -------------------------------------
3 select * from (select lsh from fp_pool_temp where zt in
4 ('1','2','3','9','E') and bzbh is null and sclx='1' and
5 scdw='150501010003LP' and fhlx='1' and cplx like '02%' and
6 glbm='150500000402' order by sxh) where rownum<=1
7
8 Plan hash value: 2965985217
9
10 -------------------------------------------------------------------------------------------------------------------------------------------------
11 | Id | Operation | Name | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | OMem | 1Mem | Used-Mem |
12 -------------------------------------------------------------------------------------------------------------------------------------------------
13 | 0 | SELECT STATEMENT | | | | | 1121 (100)| | | | |
14 |* 1 | COUNT STOPKEY | | | | | | | | | |
15 | 2 | VIEW | | 28 | 252 | | 1121 (1)| 00:00:14 | | | |
16 |* 3 | SORT ORDER BY STOPKEY | | 28 | 2716 | | 1121 (1)| 00:00:14 | 1024 | 1024 | |
17 |* 4 | TABLE ACCESS BY INDEX ROWID | FP_POOL_TEMP | 28 | 2716 | | 1120 (1)| 00:00:14 | | | |
18 | 5 | BITMAP CONVERSION TO ROWIDS | | | | | | | | | |
19 | 6 | BITMAP AND | | | | | | | | | |
20 | 7 | BITMAP CONVERSION FROM ROWIDS| | | | | | | | | |
21 |* 8 | INDEX RANGE SCAN | IDX_FP_POOL_TEMP_GLBM | 13982 | | | 49 (0)| 00:00:01 | | | |
22 | 9 | BITMAP CONVERSION FROM ROWIDS| | | | | | | | | |
23 | 10 | SORT ORDER BY | | | | 1824K| | | 65M| 2804K| 58M (0)|
24 |* 11 | INDEX RANGE SCAN | IDX_FP_POOL_TEMP_CPLX | 13982 | | | 249 (1)| 00:00:03 | | | |
25 ————————————————————————————————————————————————————————————————————————
好的执行计划是没有bitmap的就一个index就完事了,这个bitmap的转换是问题的根本原因。
但是我们首先尝试了绑定执行计划:
用下面的语句生成新的sqlid和plan
select * from (select /*+ index(t IDXEN_FP_POOL_T_SFZS) */ lsh from fp_pool_temp t where zt in ('1', '2', '3', '9', 'E') and bzbh is null and sclx='1' and scdw='150501010003LP' and fhlx='1' and cplx like '02%' and glbm='150500000402' order by sxh) where rownum<=1
然后平时用的收集表的统计信息,不涉及的列上具体信息,比如数据分布、直方图啥的,可以执行如下命令收集部分列的具体统计信息(并让原来老的清除):
exec dbms_stats.gather_table_stats('LP','FP_POOL_TEMP',method_opt=>'for columns(sclx,fhlx,zt,scdw)',no_invalidate=>false);
如果是统计信息的问题,也可以把原来老的统计信息数据泵导入进去,然后把统计信息锁死:
exec dbms_stats.lock_table_stats(ownname=>'***',tabname=>'***’)
上面的尝试提供一种思路,后面我发现问题还是处在bitmap index的转换上,oracle默认开启的这项功能在索引选择性不好的情况下会导致走错误的执行计划
当然最后还是bitmap转换的问题,有一个隐含参数,_b_tree_bitmap_plans
alter session set "_b_tree_bitmap_plans"=false; 可以观察是否有改善,然后可以修改system
这个问题就是选择性太差的索引,oracle会自动转换成bitmap,有些情况好,有些是差,可以尝试关掉看看性能。