DB : oracle 11.2.0.4
OS: Linux 2.6.32-573.12.1.el6.x86_64
发现问题
新开发的项目,上线后监控发现db主机cpu负载增加一倍,由原来的10%变成20%!
![](https://img.haomeiwen.com/i14299568/23c9f17031ebdccd.jpg)
排查问题
通过v$session 抓到正在执行的sql:
SELECT SUPP_GOODS_ID, update_time FROM SUPP_GOODS WHERE :"SYS_B_0"=:"SYS_B_1" AND update_time > :1;
有多个类似这种根据update_time条件来扫描数据的sql。
分析该表的索引发现这类表的update_time字段均没有索引,不明白为何压测能通过。
正常应该是需要走仿真环境压测,可能由于数据量原因导致问题没暴露出来。
第一反应,加上索引:
create index IDX_SUPP_GOODS_UPTIME on SUPP_GOODS (UPDATE_TIME) ;
继续观察,发现一个奇怪的现象,从数据库v$sqlarea 里抓到的sql是可以走索引的,而且找开发抓了后台日志的sql,也是ok的。但是查看ash视图,还是不走索引,于是通过cursor_id 查看真实的执行计划,如下:
![](https://img.haomeiwen.com/i14299568/a271f45a91ee945e.png)
这里发现谓词那里走了 internal_function 函数,应该是发生了隐式转换,于是查看下绑定变量的值:
![](https://img.haomeiwen.com/i14299568/de0306f25dfc7ca9.jpg)
看到DATATYPE_STRING字段,差不多可以确定问题了。
UPDATE_TIME字段类型为 date,与传入参数timestamp之间发生了隐士转换,导致索引失效。
字段类型是timestamp:
>to_date() 可以走索引;
>timestamp 可以走索引;
字段类型是date:
>to_date() 可以走索引;
>timestamp 不走索引。
所以这里就是 >timestamp 不走索引的情况,让开发改下代码,把值to_date()一下再传进来,就ok了。
观察负载情况,降下来了:
![](https://img.haomeiwen.com/i14299568/764d31bf47e55e53.jpg)
网友评论