日期:2014-05-17  浏览次数:20867 次

有关存储过程中动态sql执行慢的问题
各位高手,我现在有一个存储过程,就是从一张大表里根据时间,号码等条件查询记录,查询语句使用的是动态sql,传入的条件采用的是绑定变量,输出的是个游标。从程序中调用该过程感觉要7-8秒才能出结果,通过plsql developer中test也不是太快。可是根据查询条件,拼成静态sql则执行的就很快1秒内就出来了。静态sql的执行计划也是合理的。
所以我怀疑是不是在存储过程中,使用动态sql执行计划不对了,没有使用索引。但是怎么看调用一个存储过程的执行计划呢?是不是通过dbms_system.set_sql_trace_in_session或者10046事件就可以呢?oracle中会不会出现使用绑定变量而不使用索引的情况呢?
还有,我给存储过程中传入号码条件的时,因为可能要查询多个号码,所以使用了自定义的嵌套表类型,不知道使用这个会不会影响索引。
PS:我在号码和时间列有复合索引。

------解决方案--------------------
再补充下,
直接在窗口中执行sql和你的动态sql执行,很长的sql,
执行计划10有8,9是不一样的,因为他们解析本来就是不同的,尤其是一些写法更可能会导致动态sql执行很慢,
比如拼接字符串之类的,in("......")等等
------解决方案--------------------
1. before you set the v_sqlcmd, insert the data of sa_num stringarray into a middle table: mid_num(num varchar2(20)); 
i think the data volume is very small, so you don't need to create index on the middle table.

2. modify your v_sqlcmd like:
v_sqlcmd := 'select a.* from voice a, mid_num a 
where a.begintime between :1 and :2 
and a.num = b.num';

------解决方案--------------------
当查询条件中的时间范围较小、嵌套表数据量小的情况下,使用HINT强制索引效率会比较好,但要限制输入条件的范围,要不范围太大时使用索引效率更差。
你要使用的索引应该是号码和时间的复合索引。
不需要把时间拼起来,尽量使用绑定变量。

探讨
目前程序接口肯定不好改变,我想了两个方式,不知道是否可以?一个是在语句里加hint,让使用索引,另一个虽然使用sql但不适用绑定变量,把查询的时间拼起来,是不是能好些呢,因为时间列有一个索引。