实验环境:
系统信息:linux 6
数据库:oracle11gR1
测试表:frank.tk
测试内容:业务部门反映某个查询特别慢,语句:select * from tk where qe=5,分析慢的原因:
开启sql_trace来跟踪操作的后台递归活动,分为 a,b 两种情况,本实验采用方法vb:
a.跟踪非当前会话下的其他用户的某个session:
收集被跟踪会话信息
SQL>select sid,serial#,username,event from v$session where username is not null;
SQL>exec dbms_system.set_sql_trace_in_session(&sid,&serial#,true); --开启
被跟踪的动作执行中。。。。。。
SQL>exec dbms_system.set_sql_trace_in_session(&sid,&serial#,false;--关闭
b.跟踪当前会话
SQL>alter session set sql_trace=true;
⚠️(注意 alter system 变更影响为数据库全局)
被跟踪的活动执行。。。。。。
SQL>alter session set sql_trace=false;
查看生产的trace的位置:
SQL>select value from v$diag_info where name='Default Trace File'
确定生产的trace的名字,每个会话生成的跟踪文件的spid都是一致的,找最新生成的就行:
select spid from v$process where addr = (select paddr from v$session where sid=&sid);
通过tkprof分析产生的trace文件:
$tkprof orcl_ora_14483.trc hh.txt explain=system/123456 aggregate=yes sys=no waits=yes sort=fchela
⚠️hh.txt为通过tkprof产生的trace跟踪文件
查看hh.txt文件
通过分析hh.txt发现实验语句select * from tk where qe=5中有大量的逻辑读且where条件的索引失效,走的是全表扫描。通过查看表结构和表的索引信息发现实验语句"qe=5"过滤条件给的是数字类型的值,而表中qe字段是字符类型数据,发生隐式转换后,表索引失效,产生大量的io消耗,导致查询变慢,解决此问题要避免发生隐式转换,可以在where过滤条件的值的两侧各加一个单引号作为字符类型的数据引入可避免此问题。
⚠️sql的where条件中,等式两边类型不一致时,数据库会做一次隐式类型转换。
如果是数字类型(诸如number,double,integer等)的话,会默认的把带引号的转成数字再进行查询,也就是说带引号和不带引号是一样的。
select * from t where to_number(char_col) = num_val
oracle会从“大”类型转换到“小”类型。
oracle会在char类型的值或字段上进行to_number或to_date转换。而不会在number或date上做to_char操作。
同样,如果是字符类型,这一列都是数字,那么你不带引号的数字也会被oracle默认转成字符类型。但如果这一列不全是数字,那么必须带引号。
改写sql,重新跟踪验证判断是否正确,结果如下图。