有一个数据库应用程序存在过多的解析问题,因此需要找到产生大量硬解析的主要语句。
什么是硬解析
Oracle数据库中的硬解析(Hard Parse)是指在执行SQL语句时,数据库需要重新解析该SQL语句,并创建新的执行计划的过程。这个过程涉及到对SQL语句的完整解析、编译和生成执行计划,是数据库性能优化中的一个重要环节。以下是硬解析的详细过程:
-
语法、语义及权限检查:Oracle首先会对SQL语句进行语法检查,确保语句的拼写和结构正确无误。接着进行语义检查,验证语句中引用的对象是否存在以及执行语句的用户是否具有相应的权限。
-
查询转换:Oracle会应用不同的转换技巧,将SQL语句转换为语义上等价的其他形式。例如,
COUNT(1)
可能会被转换为COUNT(*)
,以优化查询性能。 -
根据统计信息生成执行计划:这是硬解析中最耗时的步骤。Oracle会根据数据库的统计信息,如表的大小、索引的统计数据等,来确定执行SQL语句的最佳路径,即成本最低的执行计划。
-
将游标信息(执行计划)保存到库缓存:一旦执行计划生成,Oracle会将这个执行计划保存在共享池(Shared Pool)的库缓存(Library Cache)中,以便后续相同的SQL语句可以重用这个执行计划,减少硬解析的发生。
硬解析的触发条件包括:
-
首次执行某个SQL语句时,因为数据库尚未为其生成解析结果,必须进行硬解析。 -
如果一个已经硬解析过的SQL语句对应的解析结果在共享池中被替换或因其他原因失效(例如,相关的数据库对象元数据发生变化),那么下次执行该语句时需要重新进行硬解析。 -
即使对于相同的SQL文本,如果其绑定变量值或会话环境(如当前用户的权限、NLS设置等)发生变化,导致生成的解析树或执行计划与缓存中的不一致,也会触发硬解析。 -
某些类型的SQL语句,如DDL(数据定义语言)语句,由于它们的操作通常是不可缓存的,因此总是进行硬解析。
硬解析对数据库性能有显著影响,因为它会消耗大量的CPU资源和内存,增加磁盘I/O,延长查询响应时间,降低用户体验。因此,在数据库性能优化中,通常建议尽量减少硬解析的发生,通过使用绑定变量、优化SQL语句结构等方式来提高软解析的比例,从而提升数据库的整体性能。
当必须将 SQL 语句加载到共享池中时,会发生硬解析。在这种情况下,Oracle Server 必须在共享池中分配内存并解析语句。
当共享池太小时,或者当您有没有绑定变量的不可重用 SQL 语句时,可能会发生过多的硬解析。
我们可能会想到 AWR 报告,其中有一节标题为“SQL ordered by Parse Calls”,但是这里的数值不仅是硬解析调用,而且还包含了软解析。
因此我们可以使用查询表中dba_hist_active_sess_history IN_HARD_PARSE='Y' 的语句,查出真正的硬解析语句。
查询一段时间以来硬解析次数最高语句
select INSTANCE_NUMBER,TOP_LEVEL_SQL_ID,SQL_ID,count(*)
from dba_hist_active_sess_history
where IN HARD_PARSE='Y'
and snap_id>=39072 and snap_id<=39073
and sample_time>to_date('20240814 09:09','yyyymmdd hh24:mi')
and sample_time<to_date('20240814 10:10','yyyymmdd hh24:mi')
group by INSTANCE_NUMBER,TOP_LEVEL_SQL_ID,SQL_ID
having count(*)>10
order by count(*) desc;
查询一段时间以来所有实例硬解析top语句
select TOP_LEVEL_SQL_ID,SQL_ID,count(*
from dba_hist_active_sess_history
where IN_HARD_PARSE='Y'
and snap_id>=39072 and snap_id<=39093
and sample_time>to_date('20240814 09:08','yyyymmdd hh24:mi')
and sample_time<to_date('20240814 16:15','yyyymmdd hh24:mi')
group by TOP_LEVEL_SQL_ID,SQL_ID
having count(*)>10
order by count(*) desc;
TOP_LEVEL_SQL_ID和SQL_ID
很多时候面对包或者存储过程,我们看到的"sql_id"仅仅是包或者存储过程本身的"sql_id",但对于包以及存储过程里面到底包含了哪些sql是不知道的,这时候就可以利用这一列,查出包或者存储过程里的一系列sql_id。
查询存储过程中那些sql语句慢
查询出硬解析语句为存储过程时,如何查看存储过程中的sql语句
###查询存储过程中那些语句慢
set verify on
set echo on
set lines 250
set head on
set tab off
WITH snaps AS
(SELECT /*+ materialize*/
snap_id, dbid
FROM dba_hist_snapshot
WHERE begin_interval_time > SYSDATE - &days),
obj AS
(SELECT /*+ materialize*/
object_id, subprogram_id
FROM DBA_PROCEDURES
WHERE object_name = UPPER ('&package_name')
AND procedure_name = UPPER('&procedure_name'))
SELECT /*+ push_subq(snp) opt_param('_optimizer_use_feedback' 'false') */
t.*
FROM (SELECT sql_id,
event,
a.SQL_PLAN_HASH_VALUE,
COUNT(DISTINCT sql_exec_id || sql_exec_start) calls,
count(1) cnt
FROM dba_hist_active_sess_history a
WHERE (PLSQL_ENTRY_OBJECT_ID, PLSQL_ENTRY_SUBPROGRAM_ID) IN
(SELECT object_id, subprogram_id FROM obj)
AND (dbid, SNAP_ID) IN (SELECT /*+qb_name(snp)*/
dbid, SNAP_ID
FROM snaps)
GROUP BY sql_id, SQL_PLAN_HASH_VALUE, event) t
ORDER BY sql_id, SQL_PLAN_HASH_VALUE, event, cnt DESC
/
CLEAR COLUMNS
本文由 mdnice 多平台发布