---------------------
4 - access("C"."COLLECT_ID"=TO_NUMBER(:COLLECT_ID))
5 - access("D"."MODEL_ID"="C"."MODEL_ID" AND "D"."DATA_DATE"=:DATA_DATE AND "D"."DATA_TYPE"=:DATA_TYPE AND
"D"."VALUE_FLAG"=0)
19 rows selected.
发现走了索引,但是当时为什么没有走索引呢。并且在二节点走了全表扫描,一节点走的是索引范围扫描。
该oracle数据库的版本为10.2.0.5,在11g之前没有引入ACS(Adaptive Cursor Sharing),所以这里CBO在第一次进行硬解析的时候才会窥视变量的值,并且生成执行计划,之后一直使用相同的执行计划。
这里我猜想,在2节点。第一次使用绑定变量的时候,CBO认为应该使用全表扫描效率更高,所以在以后一直使用该执行计划。然而在一节点,第一次使用绑定变量的时候,CBO认为走范围扫描效率更高。所以这里导致1节点和2节点的执行计划不一样。
找到原因了,就好办了。业务人员怕数据库负载过大导致宕机,遂叫我把该sql的相关进程(发现30个进程)全部kill掉。kill完进程后磁盘IO瞬间降到50MB。
还没有完,改sql以后还会有这种选择。我们怎么去避免?
既然了解了CBO的做法,那就触发它再一次去执行一次硬解析获得正确的执行计划。有如下4种方法:
1、alter system flush shared_pool(想跪就跑这个)
2、对相关表做DDL操作
3、重新收集统计信息
4、dbms_shared_pool.purge
前面三种方案对生产
系统都影响比较大,所以利用第四种方法。
?
?
SQL> select address,hash_value,executionsfrom v$sql where hash_value=54043712
ADDRESS HASH_VALUE EXECUTIONS
---------------- ---------- ---------- -----------
0000040229F039E0 54043712 1
SQL> alter session set events '5614566 trace name context forever';
SQL> exec dbms_shared_pool.purge('0000040229F039E0,54043712','C');
重新利用合适的绑定变量跑出正确的执行计划即可。
如何永久保持不变呢?
加hint,强制走索引。
?
?
explain plan for SELECT /*+ index(zbdba1,IDX_C_COLLECT_MD_001)* / D.MODEL_ID,
D.OBJ_ID,
D.OBJ_TYPE,
D.DATA_TYPE,
D.DATA_DATE,
D.DATA_FROM_DATE,
D.DATA_TO_DATE,
D.DATA_FLAG
FROM EIC2.zbdba1 D, EIC2.zbdba2 C
WHERE D.MODEL_ID = C.MODEL_ID
AND C.COLLECT_ID = '70350'
AND D.DATA_DATE = to_date('06/01/15','MM/DD/YY')
AND D.DATA_TYPE = '02'
AND D.VALUE_FLAG = 0;
如果以后该索引有变化,也将会失效。
?
当然优化没有一劳永逸的事情,针对大小超过50GB,数据量高达6亿条的表还是要定期检查它相关sql的执行计划。
?