oracle一条sql运行时间很长,SQL执行时反复一慢两快的问题

本文解析了一种SQL执行过程中出现的特殊现象:慢-快-快-慢...的执行速度波动,并深入探讨了两个Oracle bug(Bug14147762与Bug12980183)对SQL执行计划的影响。通过对执行计划的生成、存储及复现机制的详细分析,揭示了执行速度波动的根本原因。
部署运行你感兴趣的模型镜像

SQL执行的时间,在正常情况下应该是稳定的。如果第一次快,第二次慢,那么可能就是由于cardinality feedback的缘故,我们可以设置”_OPTIMIZER_USE_FEEDBACK”= false来规避。但是这次遇到的问题却是执行过程两快一慢,执行过程是慢->快->快->慢->快->快->慢->快->快->……,执行了慢之后,还能再快回来,这是怎么回事呢?

这个sql初次执行的时候是快的,然后把这次快的执行计划用spm固定下来,再次执行的时候,就发生了慢快快的现象。

这些现象的原因,是hint中了oracle的2个bug,我用流程图显示如下:

3394dd38d9dcc5efc2a792866998f2a3.png

稍微解释一下:

我们看到,一开始SQL发起的时候,由于cardinality feedback(CFB),且hint中Bug 14147762 Cardinality feedback causes worse plan for JPPD,(这也是通常Cardinality feedback产生第一次快后面慢的原因,可以禁用Cardinality feedback解决,但是我们不想禁用oracle的新特性,我们需要了解其中的root cause,找出解决办法),产生了坏的执行计划,后续,检查该sql语句是否在SQL Management Base(SMB)中,由于保存过搞语句及其执行计划,所以在smb中,再进一步检查执行计划是否在smb中,由于之前保存的是那个好的执行计划,因此该执行计划不在smb中。由于执行计划不在smb中,尝试reproduce,但是此时又hint中另外一个Bug 12980183 –SPM cannot reproduce execution plan(也是和语句中含有push join pred有关,因为含有JPPD,造成无法reproduce成功。其实这个bug也容易绕过,就是使用outline,不使用SPM。)。于是无法成功reproduce执行计划。无法成功reproduce原来的执行,oracle将reproduce标记为从YES改为NO,然后使用了坏的执行计划。——执行的慢。

然后我们继续跑该sql,由于reproduce状态改变,oracle重新继续解析,注意,此时CFB不会介入,在10053的trace中也可以看到没有CFB的介入,没有看到/*+ OPT_ESTIMATE */ 的hint。 此时由于没有没有CFB的介入,生成的执行计划是好的。继续检查该sql和sql的执行计划是否在SMB中,结果是语句确实在SMB中,执行计划也是在SMB中(因为是好的执行计划),将reproduce标记从NO改为YES,使用该好的执行计划,也是在SMB中的执行计划。——执行的快。

好了,我们继续跑第三次,再次由于reproduce状态改变,oracle重新解析,且CFB不介入。生成好的执行计划,继续检查该sql和sql的执行计划是否在SMB中,结果是语句确实在SMB中,执行计划也是在SMB中(因为是好的执行计划),注意,此时不需要改变reproduce的标记。然后使用该好的执行计划,所以,——执行的快。

继续执行第四次,由于之前reproduce标记未变,因此,CFB介入,此时hint中Bug 14147762,生成坏的执行计划,重复到了第一步的情况,因此出现了慢的情况。

在上述的解释中,我们基于下面的2个假设:

1. 当reproduce的状态发生的时候,CFB不介入。

2. sql的再次解析发生在:

1)reproduce status change

2)cardinality feedback take effect

1

2

3

4

1.当reproduce的状态发生的时候,CFB不介入。

2.sql的再次解析发生在:

1)reproducestatuschange

2)cardinalityfeedbacktakeeffect

最终的我们找到了一慢两快的原因,为上述的2个bug申请Patch解决(在11.2.0.3上的patch,到11.2.0.4上已经fix掉)。

您可能感兴趣的与本文相关的镜像

PyTorch 2.6

PyTorch 2.6

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

<think>嗯,我现在需要解决的问题是:为什么同一SQL语句在应用程序中执行,但在PL/SQL里却很。这个问题看起来有点常见,但具体原因可能有很多,我得仔细分析可能的原因,然后逐步排除。 首先,我应该回忆Oracle数据库的些特性,以及应用程序和PL/SQL环境之间的差异。可能的因素包括绑定变量、执行计划的不同、会话设置、统计信息、网络延迟等等。 第步,绑定变量的使用。在PL/SQL中,通常会使用绑定变量,而应用程序如果使用字面值(比如直接把值写在SQL语句里),可能会导致硬解析过多,或者优化器选择不同的执行计划。不过这里的情况相反,应用而PL/SQL,所以需要看具体情况。比如,应用是否使用了绑定变量?如果应用没有使用绑定变量,导致每次执行都要硬解析,可能会影响性能。但如果是这样,问题可能更普遍,而不仅仅是这条SQL。不过也有可能当应用使用绑定变量,优化器无法准确估计选择性,从而生成较差的执行计划。而PL/SQL可能在测试使用的具体值,使得执行计划更优。 另外,可能涉及到绑定变量窥视(Bind Peeking)的问题。在Oracle中,当使用绑定变量,第执行会窥视绑定的值,生成执行计划。如果后续的绑定值分布不均匀,可能导致执行计划不适合某些值。例如,如果应用中的某个绑定变量的值选择了个全表扫描的计划,而PL/SQL测试用的值更适合索引扫描,这可能造成差异。但如果是这种情况,可能需要检查执行计划是否不同。 第二步,检查执行计划是否真的不同。要确认在种环境中SQL执行计划是否致。可以使用SQL_ID或者SQL语句的文本,查询V$SQL视图,找到对应的执行计划。在PL/SQL中,可能使用了不同的优化器参数,比如通过会话级别的优化器_mode(如ALL_ROWS vs FIRST_ROWS),导致生成不同的计划。例如,应用程序可能使用默认的ALL_ROWS,而PL/SQL会话可能设置成FIRST_ROWS,从而更倾向于使用索引。 第三步,统计信息的问题。可能统计信息在应用执行已经过,而之后被更新,导致PL/SQL测试执行计划更好。或者,应用和PL/SQL执行时间不同,比如统计信息在某个时间段自动收集,导致执行计划变化。需要确认统计信息的最新性,以及是否存在历史统计信息的问题。 第四,会话级别的设置差异。比如,在PL/SQL中可能设置了不同的NLS参数,或者优化器相关的参数(如OPTIMIZER_INDEX_COST_ADJ,OPTIMIZER_INDEX_CACHING),这些可能影响执行计划的选择。例如,如果OPTIMIZER_INDEX_COST_ADJ设置较低,优化器可能更倾向于使用索引,而在应用中该参数可能较高,导致全表扫描。 第五,数据量和缓存的影响。当应用执行,可能数据没有被缓存到内存中,导致物理读较多,而PL/SQL执行,数据已经被缓存,因此更。需要检查执行的逻辑读和物理读情况,可以通过AWR报告或执行计划中的统计信息来比较。 第六,网络延迟。应用程序可能通过网络连接数据库,而PL/SQL工具(如SQL*Plus、PL/SQL Developer)在本地执行,网络延迟可能导致应用的整体响应时间变长。虽然这不会直接影响SQL执行时间,但用户感知的延迟可能更长。需要确认问题中的“”是指SQL执行时间还是应用程序的响应时间。可以通过在数据库端查看SQL的实际执行时间来判断。 第七,事务隔离级别或锁竞争。应用可能在执行SQL,遇到了锁等待,或者处于不同的事务隔离级别,导致需要处理更多的undo数据或行版本控制,从而变。而PL/SQL测试可能没有这些并发问题。需要检查等待事件(如enq: TX - row lock contention)是否在应用执行出现。 第八,应用可能使用了不同的游标类型。比如,使用分页查询,应用可能使用次性获取所有数据,而PL/SQL工具可能分批获取,导致应用端感觉更。或者,应用程序的游标设置(如预取行数)不同,影响数据检索的速度。 第九,绑定变量类型不匹配。比如,应用中的绑定变量类型与表字段类型不致,导致隐式转换,从而无法使用索引。例如,表字段是VARCHAR2,但应用绑定的是数字类型,导致转换,进而全表扫描。而PL/SQL中可能正确使用了相同类型,从而使用索引。 第十,SQL解析的不同情况。比如,在PL/SQL中,SQL可能是静态SQL,而应用中使用的是动态SQL,这可能导致不同的解析方式。不过这可能影响解析时间,不太可能对执行计划产生重大影响,除非涉及到不同的优化器设置。 解决这个问题的步骤可能包括: 1. 获取两次执行(应用和PL/SQL)的实际执行计划,比较是否不同。 2. 检查绑定变量的类型和值,是否存在差异。 3. 检查会话参数设置,如OPTIMIZER_MODE等。 4. 查看统计信息是否最新,是否存在直方图。 5. 检查是否有锁或等待事件。 6. 观察执行的资源消耗(逻辑读、物理读、CPU时间等)。 具体操作可能包括: - 在应用中启用跟踪(如10046事件),或者在数据库中找到该SQLSQL_ID,然后生成执行计划。 - 使用DBMS_XPLAN.DISPLAY_CURSOR查看实际执行计划。 - 检查V$SQL中的执行统计信息,比较两次执行的ELAPSED_TIME、EXECUTIONS、BUFFER_GETS等。 - 使用SQLT或其他性能分析工具进行深入分析。 总结可能的原因,比如绑定变量类型或值的不同导致执行计划差异,会话参数设置不同,统计信息问题,缓存差异,或锁竞争等。需要系统地进行逐排查。</think>在Oracle数据库中,同一SQL语句在应用程序中执行但在PL/SQL环境中运行迅速,通常由以下原因导致: --- ### **1. 绑定变量差异** - **绑定变量窥视(Bind Peeking)**: Oracle在首次执行绑定变量的SQL会根据传入的值生成执行计划。若应用中的绑定值分布不均(如首次传入的值导致选择了全表扫描,而后续值更适合索引),可能导致执行计划不优。而PL/SQL测试可能使用特定值生成了更优计划。 - **类型不匹配**: 应用中的绑定变量类型可能与表字段类型不致(如字符串绑定为数字),触发隐式转换,导致无法使用索引。 --- ### **2. 执行计划差异** - **会话参数不同**: 应用会话可能设置了不同的优化器参数(如`OPTIMIZER_MODE=ALL_ROWS`,优先吞吐量),而PL/SQL会话可能使用`FIRST_ROWS`(优先响应速度),导致选择索引而非全表扫描。 - **统计信息过**: 应用执行统计信息未更新(如数据分布变化后未收集),而PL/SQL测试前已更新统计信息,优化器选择了更优计划。 --- ### **3. 缓存与资源消耗** - **数据缓存(Buffer Cache)**: PL/SQL测试数据已缓存到内存,而应用首次执行需从磁盘读取,物理I/O增加。 - **执行计划缓存**: 应用可能因未使用绑定变量导致频繁硬解析,而PL/SQL使用绑定变量复用执行计划。 --- ### **4. 网络与游标设置** - **网络延迟**: 应用程序需要通过网络传输结果集,而PL/SQL工具(如SQL*Plus)在本地执行,延迟更低。 - **游标预取(Fetch Size)**: 应用可能次性获取全部数据(如JDBC默认fetchSize较小),而PL/SQL工具分批次高效获取。 --- ### **5. 锁与并发问题** - **锁竞争(Lock Contention)**: 应用运行可能遇到行锁或表锁,导致等待(如`enq: TX - row lock contention`),而PL/SQL测试无并发操作。 --- ### **6. 隐式参数与会话设置** - **NLS或格式设置**: 应用的NLS_DATE_FORMAT等设置可能导致隐式转换,影响索引使用。 - **资源限制(Resource Manager)**: 应用所属用户组可能有资源限制(如CPU、I/O优先级),而PL/SQL测试用户无限制。 --- ### **排查步骤** 1. **比较执行计划** ```sql -- 在PL/SQL和应用中分别执行以下操作 EXPLAIN PLAN FOR [你的SQL]; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY()); -- 或通过SQL_ID获取实际执行计划 SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('sql_id')); ``` 2. **检查绑定变量** 使用`V$SQL_BIND_CAPTURE`查看历史绑定值: ```sql SELECT name, value_string, datatype_string FROM v$sql_bind_capture WHERE sql_id = '你的SQL_ID'; ``` 3. **分析会话参数** 对比应用会话和PL/SQL会话的优化器参数: ```sql -- 查询当前会话参数 SELECT name, value FROM v$parameter WHERE name LIKE 'optimizer%'; ``` 4. **跟踪SQL执行** 在应用中启用10046事件跟踪: ```sql ALTER SESSION SET events '10046 trace name context forever, level 12'; -- 执行SQL后关闭跟踪 ALTER SESSION SET events '10046 trace name context off'; ``` 5. **检查等待事件** 查询`V$SESSION_WAIT`或AWR报告,确认是否存在锁、I/O等待等。 --- ### **解决方案** - **强制绑定变量**:确保应用使用绑定变量,避免硬解析。 - **优化统计信息**:定期收集统计信息,必要使用动态采样。 - **固定执行计划**:若计划不稳定,使用SQL Profile或SPM固定最佳计划。 - **调整游标设置**:增大JDBC的`fetchSize`减少网络交互次数。 - **参数调优**:在会话级别设置`OPTIMIZER_INDEX_COST_ADJ`等参数优化索引选择。 通过系统排查执行计划、绑定变量、会话参数和资源竞争,通常能定位到根本原因并针对性优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值