这是我的问题:我们有一个称为的存储过程,HEAVY_SP
并且根据其执行方式,执行时间会大大增加:
(1)通话执行
在Oracle SQL Developer IDE中直接执行
CALL HEAVY_SP(0, 'F', 5, ...)
需要15秒(我们当前的解决方案)
(2)使用播放按钮
使用Oracle SQL Developer打开过程并执行“播放”按钮:
需要15秒
(3) dbms_job:计划模式
需要15秒
(4) dbms_job:即时执行模式
需要超过1个小时
回顾数据处理方式,我们发现每次迭代都很慢。
(5)从SQL_PLUS(Linux)
耗时超过1小时,迭代速度非常慢
(6)从JAVA
耗时超过1小时,迭代速度非常慢
(7)从TOAD
耗时超过1小时,迭代速度非常慢
研究
我们已经吃了很多Google页面,例如:
为什么在存储过程中查询运行比在查询窗口中慢
oracle-pl-sql-procedure-runs比SQL慢
甲骨文在存储过程中插入的速度比手动插入要慢
通过Java相对于直接在数据库上运行,存储过程运行30慢一些
所以我的问题是:
为什么Oracle采取这种方式?
它不应该在所有情况下(相同的参数)都表现得很快吗?
存储过程必须修改吗?
如果查询计划,跟踪文件或统计信息显示不同的行为,则存储过程是否必须固定?
为什么在查询窗口中执行速度很快?
提前致谢。
提示1
遵循@BobJarvis关于统计的建议
结果:我们的统计数据是最新的。甚至,我们EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SOME_USER', tabname=>'SOME_TABLE', cascade => TRUE);
在所有问题表中重新执行,结果是相同的。
提示#2
遵循@KonstantinSorokin的建议
我怀疑执行计划可能会因会话设置的不同而有所不同。考虑比较v$ses_optimizer_env
结果:我们进行了比较,结果(1)和(4)的v $ ses_optimizer_env相同。
提示3
使用此查询:
select s.sid,s.serial#,s.username, s.machine,replace(q.SQL_FULLTEXT,chr(0)) sql_text, s.program, s.logon_time, s.status, s.OSUSER from v$session s, v$sql q where s.status='ACTIVE' and s.username is not null and s.sql_hash_value = q.hash_value order by s.LOGON_TIME, s.username;
我注意到机器,程序和其他更改取决于测试:
快速模式(查询窗口)
machine | program | ouser --------------------|------------------ | ------- my laptop username | SQL DEVELOPER | User
滞后模式(后台执行)
machine | program | ouser --------------------|------------------ | ------- ip-10-6-7-1 | oracle@ip-10-6-7-1| rdsdb
提示#4
遵循@KonstantinSorokin与痕迹相关的建议。
结果:临时DBA进行了调查,他告诉我们某些sql_id具有不同的执行计划。他的建议是:使用提示。
这可能是解决方案,但是,为什么某些SQL ID具有不同的执行计划?
感谢@ IsaacMejia,NLS_COMP = LINGUISTIC是缓慢执行的原因。因此,java不是问题的原因。Oracle错误配置是导致我们出现问题的原因。
解决方案必须在实例级别为NLS_COMP = BINARY设置正确的值。
但就我而言,我有几个应用程序可以很好地处理此值。因此,为了避免应用程序中的排序和比较问题,我无法覆盖实例NLS设置。
临时解决方案在存储过程的开头执行:
execute immediate 'alter session set NLS_COMP=''BINARY''';
并在完成时返回到先前的值:
execute immediate 'alter session set NLS_COMP=''LINGUISTIC''';
现在,存储过程可以像在查询窗口中直接执行一样快速运行(ORACLE SQL DEVELOPER)