为什么oracle存储过程的执行时间会大大增加取决于它是如何执行的?

Why oracle stored procedure execution time is greatly increased depending on how it is executed?

这是我的问题:我们有一个名为 HEAVY_SP 的存储过程,根据它的执行方式,执行时间会大大增加:

(1)调用执行

在 Oracle 中直接执行 SQL 开发人员 IDE

CALL HEAVY_SP(0, 'F', 5, ...)

需要 15 秒(我们当前的解决方案)

(2) 使用 播放 按钮

正在使用 Oracle SQL Developer 打开程序并执行 "play" 按钮:

需要 15 秒

(3) dbms_job : 计划模式

需要 15 秒

(4) dbms_job : 即时执行模式

需要 1 个多小时

查看数据的处理方式,发现每次迭代都非常慢。

(5) 来自 SQL_PLUS (linux)

需要 1 个多小时,迭代非常慢

(6) 来自 JAVA

需要 1 个多小时,迭代非常慢

(7) 来自 TOAD

需要 1 个多小时,迭代非常慢

研究

我们吃了很多google页如下:

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

所以我的问题是:

提前致谢。


来自评论的提示

TIP #1

遵循 @BobJarvis 关于统计的建议

结果:我们的统计数据是最新的。甚至,我们在所有有问题的表中重新执行EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SOME_USER', tabname=>'SOME_TABLE', cascade => TRUE);,结果是一样的。


TIP #2

遵循 @KonstantinSorokin

的建议

我怀疑执行计划可能因会话设置的不同而不同。考虑比较 v$ses_optimizer_env

Result :我们已经比较了结果 v$ses_optimizer_env 对于 (1 )(4) 场景。


TIP #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;

我注意到机器、程序和用户会根据测试发生变化:

快速模式(查询window)

machine             | program           | ouser
--------------------|------------------ | -------
my laptop username  | SQL DEVELOPER     | User

滞后模式(后台执行)

machine             | program           | ouser
--------------------|------------------ | -------
ip-10-6-7-1         | oracle@ip-10-6-7-1| rdsdb

TIP #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''';

和 return 到完成时的先前值:

execute immediate 'alter session set NLS_COMP=''LINGUISTIC''';

现在存储过程 运行 与直接在查询中执行一样快 window (ORACLE SQL DEVELOPER)

尝试从不同的情况(ide 或 java 程序)获取 nls 参数,它们必须不同

select * from NLS_SESSION_PARAMETERS

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

  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 将使您的排序和比较不区分重音和区分大小写。