【发布时间】:2017-06-10 00:53:32
【问题描述】:
这是我的问题:我们有一个名为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个多小时,迭代很慢
研究
我们吃过很多谷歌页面如下:
why-does-a-query-run-slower-in-a-stored-procedure-than-in-the-query-window
oracle-pl-sql-procedure-runs-slower-than-sql
oracle-insert-in-stored-procedure-very-slow-compared-to-insert-run-manually
stored-proc-running-30-slower-through-java-versus-running-directly-on-database
所以我的问题是:
- 为什么 Oracle 会这样做?
- 它不应该在所有情况下都表现得很快(相同的参数)吗?
- 必须修改存储过程?
- 如果查询计划、跟踪文件或统计信息显示不同的行为,是否必须修复存储过程?
- 为什么在查询窗口中执行速度很快?
提前致谢。
来自 cmets 的提示
提示 #1
遵循@BobJarvis关于统计数据的建议
结果:我们的统计数据是最新的。甚至,我们在所有有问题的表中都执行了EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SOME_USER', tabname=>'SOME_TABLE', cascade => TRUE);,结果是一样的。
提示 #2
遵循@KonstantinSorokin
的建议我怀疑执行计划可能会因会话设置的不同而不同。考虑比较v$ses_optimizer_env
结果 :我们进行了比较,结果 v$ses_optimizer_env 对于 (1) 和 (4) 是相同的强>场景。
提示 #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;
我注意到机器、程序和用户因测试而异:
FAST MODE(查询窗口)
machine | program | ouser
--------------------|------------------ | -------
my laptop username | SQL DEVELOPER | User
LAG MODE(后台执行)
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)
【问题讨论】:
-
所有不同调用的参数是否相同,无论是快的还是慢的,还是参数不同?存储过程使用(直接或间接)的所有表是多久前被分析的?
DBMS_STATS.GATHER_TABLE_STATISTICS为每个表提供了哪些参数? -
我的猜测是某处存在隐式类型转换,这取决于会话特定设置,例如 NLS_DATE_FORMAT。例如,如果代码看起来像
... and date_column = '01/01/2000',它的工作方式可能会有所不同,具体取决于客户端默认设置。可以分享一下代码吗? -
我不确定我是否理解“永无止境,迭代缓慢”。如果迭代很慢,那么它必须在某个时间结束?存储过程有什么作用?它是否发出一条或多条 SQL 语句?如果是这样,你能分享这些,以及他们的执行计划吗?如果不止一个,你能把它缩小到一个冒犯性的陈述吗?
-
嗨@bob-jarvis。感谢您的反馈意见。 (1) 是的,所有测试的参数都相同。(2) 表格是日常使用的。 (3) 我们还没有开始统计。如果我们选择这种方式解决问题,我会分享它。
-
我怀疑执行计划可能会因会话设置的不同而不同。考虑比较
v$ses_optimizer_env、v$parameter
标签: java oracle stored-procedures oracle-sqldeveloper toad