【问题标题】:Why oracle stored procedure execution time is greatly increased depending on how it is executed?为什么 oracle 存储过程的执行时间会随着执行方式的不同而大大增加?
【发布时间】: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_envv$parameter

标签: java oracle stored-procedures oracle-sqldeveloper toad


【解决方案1】:

尝试从您的不同案例(ide 或 java 程序)中获取 nls 参数,它们必须不同

select * from NLS_SESSION_PARAMETERS

然后在您的存储过程中设置变量以使它们在最快的情况下相等。

  execute immediate 'alter session set NLS_SORT=''SPANISH''';

一旦你的 SP 拥有所有 nls 参数。它会运行得很快。

我最近在Alter session slows down the query through Hibernate 发现了一个类似的案例。但在他们的情况下,他们改变了 de 参数,然后变慢了。

我调查发现参数 NLS_COMP y NLS_SORT 可能会影响 oracle 如何使用字符串的执行计划(在比较或排序时)

当 NLS_COMP 被定义为 LINGUISTIC 时,它将使用 NLS_SORT 中定义的语言。

例如,如果 NLS_COMP = LINGUISTIC 和 NLS_SORT=BINARI_AI 您的查询 是

select * from table where string_column like 'HI%'

在内部它会做

select * from table where  
NLSSORT(string_column,'BINARI_AI') >= HEXTORAW('324242432')
NLSSORT(string_column,'BINARI_AI') >= HEXTORAW('675757576')

所以如果你没有 NLSSORT(column,'BINARI_AI') 的索引,它会很慢。

知道 NLS_SORT=BINARY_AI 将使您的排序和比较不区分重音和区分大小写。

【讨论】:

  • 感谢@IsaacMejia。我会试试的。
  • 嗨@IsaacMejia,你是对的。 NLS_COMP=LINGUISTIC 是执行缓慢的原因。设置为 BINARY 值后,存储过程运行速度快于直接在查询窗口中执行(ORACLE SQL DEVELOPER)。非常感谢!!
猜你喜欢
  • 2016-09-22
  • 1970-01-01
  • 2019-02-02
  • 1970-01-01
  • 2011-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
相关资源
最近更新 更多