暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SQL 执行计划为何频繁变动?揭秘 Oracle 硬解析的五大原因

数据库驾驶舱 2024-09-04
438

在数据库管理中,性能问题是每位 DBA 都绕不开的挑战。尤其是在 Oracle 数据库中,突然出现的 SQL 执行计划变化可能会导致性能骤降。那么,是什么原因导致 SQL 需要重新硬解析,进而生成新的执行计划呢?本文将详细探讨几种常见的硬解析原因,帮助你更好地优化和诊断数据库性能。


「1. 自动收集统计信息」

为了确保 SQL 语句的最佳执行性能,Oracle 会根据当前的统计信息来生成最优的执行计划。在基于成本的优化器(CBO)模式下,数据库需要了解最新的统计信息,如表的行数、块数、字段的选择性等。因此,Oracle 每天都会自动运行一个统计信息收集任务,收集表中数据变化超过 10% 的最新统计信息。

在新统计信息收集完成后,相关 SQL 语句在执行时可能会进行硬解析。Oracle 设计了一个巧妙的机制,当某个 SQL 执行时,如果发现依赖的对象最近收集过统计信息,系统会在随机的时间戳内打上标记。当 SQL 在下次解析时,Oracle 会检查时间戳,如果超过了设定的时间(例如 5 小时),便会触发硬解析。


「2. 绑定变量不匹配导致的 Child Cursor 生成」

Oracle 在解析带有绑定变量的 SQL 时,会记录第一次硬解析时的绑定变量相关元数据。如果后续的 SQL 解析时发现绑定变量的类型或长度不匹配,Oracle 会生成一个新的 child cursor 并进行硬解析。

例如,scott下有一个表 emp
,并使用以下代码来插入和查询数据:

VAR a1 CHAR(20);
EXEC :a1 := 'CLERK'

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
select count(*from emp where job=:a1;

  COUNT(*)
----------
         0

Elapsed: 00:00:00.00

执行后,你可以通过以下 SQL 语句查看生成的 cursor
SELECT sql_id, child_number, first_load_time FROM V$SQL WHERE SQL_TEXT LIKE '%count%emp%';

SQL_ID        CHILD_NUMBER FIRST_LOAD_TIME
------------- ------------ ----------------------------------------------------------------------------
9s2kfv5bd4jwm            0 2024-09-04/17:50:13


Elapsed: 00:00:00.04

如果将绑定变量类型改为 `VARCHAR2` 并再次执行同样的查询,Oracle 会生成一个新的 child cursor,并进行硬解析。通过以下查询可以查看产生新的 child cursor 的原因:

VAR a1 VARCHAR2(20);
EXEC :a1 := 'CLERK'

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
18:37:36 SCOTT@qihuo> select count(*from emp where job=:a1;

  COUNT(*)
----------
         4

Elapsed: 00:00:00.00

SELECT sql_id, child_number, bind_mismatch FROM v$sql_shared_cursor WHERE ROWNUM < 10 AND sql_id = '9s2kfv5bd4jwm';

SQL_ID        CHILD_NUMBER B
------------- ------------ -
9s2kfv5bd4jwm            0 N
9s2kfv5bd4jwm            1 Y

结果中 bind_mismatch
字段为 Y
,说明绑定变量不匹配导致了硬解析。


「3. 自适应游标共享(Adaptive Cursor Sharing)」

在 Oracle 11g 中引入了自适应游标共享功能。当表上的字段存在直方图且数据存在倾斜时,不同的数据输入可能导致 Oracle 尝试进行硬解析,以便生成更合适的执行计划。


「4. Cursor 被 Age Out」

Oracle 采用了类似操作系统的 LRU(Least Recently Used)算法来管理内存。Shared Pool 中的内存块(Chunk)如果在 Free List 上没有合适大小的内存块时,系统会触发清理机制。若某个 cursor 申请的内存块被清理掉,下次执行该 SQL 时就会重新进行硬解析。

需要注意的是,这个清理机制是 Oracle 内部的内存管理机制,并不是操作系统层面的 swap 机制。


「5. 人为因素引发的硬解析」

除了 Oracle 内部机制外,人为操作也可能导致硬解析。例如,手动收集统计信息、执行 flush shared_pool
操作、调用 dbms_shared_pool.purge
清理 cursor、执行 DDL 语句等,都会引发硬解析。


「总结」

硬解析是 Oracle 数据库中一个重要但复杂的过程。了解和避免不必要的硬解析,对于优化数据库性能至关重要。通过本文的介绍,相信你对硬解析的原因有了更清晰的认识,能够更好地进行 SQL 优化和数据库管理。

「欢迎关注我们的公众号,获取更多技术分享与经验交流。」


文章转载自数据库驾驶舱,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论