PLSQL_性能优化系列06_Oracle Soft Parse / Hard Parse软硬解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 2014-08-11 Createed By BaoXinjian 一、摘要 Oracle硬解析和软解析是我们经常遇到的问题,所以需要考虑何时产生软解析何时产生硬解析,如何判断   1. SQL的执行过程 当发布一条SQL或PL/SQL命令时,Oracle会自动寻找该命令是否存在于共享池中来决定对当前的语句使用硬解析或软解析。

2014-08-11 Createed By BaoXinjian

一、摘要


Oracle硬解析和软解析是我们经常遇到的问题,所以需要考虑何时产生软解析何时产生硬解析,如何判断

 

1. SQL的执行过程

当发布一条SQL或PL/SQL命令时,Oracle会自动寻找该命令是否存在于共享池中来决定对当前的语句使用硬解析或软解析。

通常情况下,SQL语句的执行过程如下:

Step1. SQL代码的语法(语法的正确性)及语义检查(对象的存在性与权限)。

Step2. 将SQL代码的文本进行哈希得到哈希值。

Step3. 如果共享池中存在相同的哈希值,则对这个命令进一步判断是否进行软解析,否则到e步骤。

Step4. 对于存在相同哈希值的新命令行,其文本将与已存在的命令行的文本逐个进行比较。

    这些比较包括大小写,字符串是否一致,空格,注释等,如果一致,则对其进行软解析,转到步骤Step6,无需再次硬解析。

    否则到步骤Step5。

Step5. 硬解析,生成执行计划。

Step6. 执行SQL代码,返回结果。

 

2. Oracle对此sql将进行几个步骤的处理过程:

Step1. 语法检查(syntax check)

  检查此sql的拼写是否语法。

Step2. 语义检查(semantic check)

  诸如检查sql语句中的访问对象是否存在及该用户是否具备相应的权限。

Step3、对sql语句进行解析(parse)

  利用内部算法对sql进行解析,生成解析树(parse tree)及执行计划(execution plan)。

Step4、执行sql,返回结果(execute and return)

 

3. 硬解析的危害:

(1) 占用资源更多,执行慢,因为不会重用已解析好的query plan。

(2) 硬解析导致library cache上的latch竞争,这会降低系统的并发性,使oracle无法充分利用系统资源。(此时即使系统资源看上去不忙,oracle也会很慢)。

(3) 一个有很多硬解析的简单应用可能导致数据库所有应用变慢。

 

4. 总结

      其中,软、硬解析就发生在第三个过程里(对sql语句进行解析parse)。

  Oracle利用内部的hash算法来取得该sql的hash值,然后在library cache里查找是否存在该hash值;

  假设存在,则将此sql与cache中的进行比较;

  假设“相同”,就将利用已有的解析树与执行计划,而省略了优化器的相关工作。这也就是软解析的过程。

  诚然,如果上面的2个假设中任有一个不成立,那么优化器都将进行创建解析树、生成执行计划的动作。这个过程就叫硬解析。

  创建解析树、生成执行计划对于sql的执行来说是开销昂贵的动作,所以,应当极力避免硬解析,尽量使用软解析。

 

二、软解析


Oracle中SQL语句执行过程中,Oracle内部解析原理如下:

1、当一用户第一次提交一个SQL表达式时,Oracle会将这SQL进行Hard parse,这过程有点像程序编译,检查语法、表名、字段名等相关信息(如下图),这过程会花比较长的时间,因为它要分析语句的语法与语义。然后获得最优化后的执行计划(sql plan),并在内存中分配一定的空间保存该语句与对应的执行计划等信息。

 

2、当用户第二次请求或多次请求时,Oracle会自动找到先前的语句与执行计划,而不会进行Hard parse,而是直接进行Soft parse(把语句对应的执行计划调出,然后执行),从而减少数据库的分析时间。

注意的是:Oracle中只能完全相同的语句,包大小写、空格、换行都要求一样时,才会重复使用以前的分析结果与执行计划。

 

3、对于大量的、频繁访问的SQL语句,如果不采用Bind 变量的方式,哪Oracle会花费大量的Shared latch与CPU在做Hard parse处理,所以,要尽量提高语句的重用率,减少语句的分析时间,通过了解Oracle SQL语句的分析过程可以明白Oracle的内部处理逻辑,并在设计与实现上避免。

在用JDBC或其它持久化数据(如Hibernate,JDO等)操作时,尽量用占位符(?)

 

4、解析过程图

 

5、总结

ORACLE sql 的处理过程大致如下:

  • 1.运用HASH算法,得到一个HASH值,这个值可以通过V$SQLAREA.HASH_VALUE 查看
  • 2.到shared pool 中的 library cache 中查找是否有相同的HASH值,如果存在,则无需硬解析,进行软解析
  • 3.如果shared pool不存在此HASH值,则进行语法检查,查看是否有语法错误
  • 4.如果没有语法错误,就进行语义检查,检查该SQL引用的对象是否存在,该用户是否具有访问该对象的权限
  • 5.如果没有语义错误,对该SQL进行解析,生成解析树,执行计划
  • 6.生成ORACLE能运行的二进制代码,运行该代码并且返回结果给用户

硬解析和软解析都在第5步进行

硬解析通常是昂贵的操作,大约占整个SQL执行的70%左右的时间,硬解析会生成执行树,执行计划,等等。

当再次执行同一条SQL语句的时候,由于发现library cache中有相同的HASH值,这个时候不会硬解析,而会软解析,

那么软解析究竟是干了什么呢?其实软解析就是跳过了生成解析树,生成执行计划这个耗时又耗CPU的操作,直接利用生成的执行计划运行该SQL语句。

 

三、软解析


1.下面的三个查询语句,不能使用相同的共享SQL区。尽管查询的表对象使用了大小写,但Oracle为其生成了不同的执行计划

select * from emp;

select * from Emp; select * from EMP;

2.类似的情况,下面的查询中,尽管其where子句empno的值不同,Oracle同样为其生成了不同的执行计划       

select * from emp where empno=7369 select * from emp where empno=7788

3.在判断是否使用硬解析时,所参照的对象及schema应该是相同的,如果对象相同,而schema不同,则需要使用硬解析,生成不同的执行计划

sys@ASMDB> select owner,table_name from dba_tables where table_name like 'TB_OBJ%'; OWNER TABLE_NAME ------------------------------ ------------------------------ USR1 TB_OBJ --两个对象的名字相同,当所有者不同 SCOTT TB_OBJ
usr1@ASMDB> select * from tb_obj; scott@ASMDB> select * from tb_obj; --此时两者都需要使用硬解析以及走不同的执行计划

 

四、硬解析


硬 解析即整个SQL语句的执行需要完完全全的解析,生成执行计划。而硬解析,生成执行计划需要耗用CPU资源,以及SGA资源。在此不得不提的是对库缓存中 闩的使用。闩是锁的细化,可以理解为是一种轻量级的串行化设备。当进程申请到闩后,则这些闩用于保护共享内存的数在同一时刻不会被两个以上的进程修改。在 硬解析时,需要申请闩的使用,而闩的数量在有限的情况下需要等待。大量的闩的使用由此造成需要使用闩的进程排队越频繁,性能则逾低下。

1. 下面对上面的两种情形进行演示

在两个不同的session中完成,一个为sys帐户的session,一个为scott账户的session,不同的session,其SQL命令行以不同的帐户名开头

如" sys@ASMDB> "  表示使用时sys帐户的session," scott@ASMDB> "表示scott帐户的session

sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --当前的硬解析值为569 parse count (hard) 64 569 scott@ASMDB> select * from emp; sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --执行上一个查询后硬解析值为570,解析次数增加了一次 parse count (hard) 64 570 scott@ASMDB> select * from Emp; sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --执行上一个查询后硬解析值为571 parse count (hard) 64 571 scott@ASMDB> select * from EMP;
sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --执行上一个查询后硬解析值为572 parse count (hard) 64 572 scott@ASMDB> select * from emp where empno=7369; sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --执行上一个查询后硬解析值为573 parse count (hard) 64 573 scott@ASMDB> select * from emp where empno=7788; --此处原来empno=7369,复制错误所致,现已更正为7788@20130905 sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --执行上一个查询后硬解析值为574 parse count (hard) 64 574

从上面的示例中可以看出,尽管执行的语句存在细微的差别,但Oracle还是为其进行了硬解析,生成了不同的执行计划。即便是同样的SQL语句,而两条语句中空格的多少不一样,Oracle同样会进行硬解析。 

 

五、硬解析改进 - 使用动态语句


1. 更改参数cursor_sharing

        参数cursor_sharing决定了何种类型的SQL能够使用相同的SQL area

        CURSOR_SHARING = { SIMILAR | EXACT | FORCE }    

            EXACT      --只有当发布的SQL语句与缓存中的语句完全相同时才用已有的执行计划。

            FORCE      --如果SQL语句是字面量,则迫使Optimizer始终使用已有的执行计划,无论已有的执行计划是不是最佳的。

            SIMILAR   --如果SQL语句是字面量,则只有当已有的执行计划是最佳时才使用它,如果已有执行计划不是最佳则重新对这个SQL

                            --语句进行分析来制定最佳执行计划。

        可以基于不同的级别来设定该参数,如ALTER SESSION, ALTER SYSTEM

sys@ASMDB> show parameter cursor_shar             --查看参数cursor_sharing NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ cursor_sharing string EXACT sys@ASMDB> alter system set cursor_sharing='similar'; --将参数cursor_sharing的值更改为similar  sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --当前硬解析的值为865 parse count (hard) 64 865 scott@ASMDB> select * from dept where deptno=10; sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --执行上一条SQL查询后,硬解析的值变为866 parse count (hard) 64 866 scott@ASMDB> select * from dept where deptno=20;
sys@ASMDB> select name,class,value from v$sysstat where statistic#=331; NAME CLASS VALUE -------------------- ---------- ---------- --执行上一条SQL查询后,硬解析的值没有发生变化还是866 parse count (hard) 64 866 sys@ASMDB> select sql_text,child_number from v$sql -- 在下面的结果中可以看到SQL_TEXT列中使用了绑定变量:"SYS_B_0" 2 where sql_text like 'select * from dept where deptno%'; SQL_TEXT CHILD_NUMBE -------------------------------------------------- ------------ select * from dept where deptno=:"SYS_B_0" 0 sys@ASMDB> alter system set cursor_sharing='exact'; --将cursor_sharing改回为exact --接下来在scott的session 中执行deptno=40 和的查询后再查看sql_text,当cursor_sharing改为exact后,每执行那个一次 --也会在v$sql中增加一条语句 sys@ASMDB> select sql_text,child_number from v$sql 2 where sql_text like 'select * from dept where deptno%'; SQL_TEXT CHILD_NUMBER -------------------------------------------------- ------------ select * from dept where deptno=50 0 select * from dept where deptno=40 0 select * from dept where deptno=:"SYS_B_0" 0

 

2. 使用绑定变量的方式

绑定变量要求变量名称,数据类型以及长度是一致,否则无法使用软解析

(1). 绑定变量(bind variable)是指在DML语句中使用一个占位符,即使用冒号后面紧跟变量名的形式,如下

            select * from emp where empno=7788    --未使用绑定变量

            select * from emp where empono=:eno   --:eno即为绑定变量

            在第二个查询中,变量值在查询执行时被提供。该查询只编译一次,随后会把查询计划存储在一个共享池(库缓存)中,以便以后获取和重用这个查询计划。

(2). 下面使用了绑定变量,但两个变量其实质是不相同的,对这种情形,同样使用硬解析

            select * from emp where empno=:eno;

            select * from emp where empno=:emp_no

           使用绑定变量时要求不同的会话中使用了相同的回话环境,以及优化器的规则等 

scott@ASMDB> create table tb_test(col int); --创建表tb_test  scott@ASMDB> create or replace procedure proc1 --创建存储过程proc1使用绑定变量来插入新记录 2 as 3 begin 4 for i in 1..10000 5 loop 6 execute immediate 'insert into tb_test values(:n)' using i; 7 end loop; 8 end; 9 /
Procedure created. scott@ASMDB> create or replace procedure proc2 --创建存储过程proc2,未使用绑定变量,因此每一个SQL插入语句都会硬解析 2 as 3 begin 4 for i in 1..10000 5 loop 6 execute immediate 'insert into tb_test values('||i||')'; 7 end loop; 8 end; 9 / Procedure created. scott@ASMDB> exec runstats_pkg.rs_start PL/SQL procedure successfully completed. scott@ASMDB> exec proc1; PL/SQL procedure successfully completed. scott@ASMDB> exec runstats_pkg.rs_middle; PL/SQL procedure successfully completed. scott@ASMDB> exec proc2; PL/SQL procedure successfully completed. scott@ASMDB> exec runstats_pkg.rs_stop(1000); Run1 ran in 1769 hsecs Run2 ran in 12243 hsecs --run2运行的时间是run1的/1769≈倍 run 1 ran in 14.45% of the time Name Run1 Run2 Diff LATCH.SQL memory manager worka 410 2,694 2,284 LATCH.session allocation 532 8,912 8,380 LATCH.simulator lru latch 33 9,371 9,338 LATCH.simulator hash latch 51 9,398 9,347 STAT...enqueue requests 31 10,030 9,999 STAT...enqueue releases 29 10,030 10,001 STAT...parse count (hard) 4 10,011 10,007 --硬解析的次数,前者只有四次 STAT...calls to get snapshot s 55 10,087 10,032 STAT...parse count (total) 33 10,067 10,034 STAT...consistent gets 247 10,353 10,106 STAT...consistent gets from ca 247 10,353 10,106 STAT...recursive calls 10,474 20,885 10,411 STAT...db block gets from cach 10,408 30,371 19,963 STAT...db block gets 10,408 30,371 19,963 LATCH.enqueues 322 21,820 21,498 --闩的队列数比较 LATCH.enqueue hash chains 351 21,904 21,553 STAT...session logical reads 10,655 40,724 30,069 LATCH.library cache pin 40,348 72,410 32,062 --库缓存pin LATCH.kks stats 8 40,061 40,053 LATCH.library cache lock 318 61,294 60,976 LATCH.cache buffers chains 51,851 118,340 66,489 LATCH.row cache objects 351 123,512 123,161 LATCH.library cache 40,710 234,653 193,943 LATCH.shared pool 20,357 243,376 223,019 Run1 latches total versus runs -- difference and pct Run1 Run2 Diff Pct 157,159 974,086 816,927 16.13% --proc2使用闩的数量也远远多于proc1,其比值是.13% PL/SQL procedure successfully completed.

 

 (3). 使用绑定变量的好处

  • 由上面的示例可知,在未使用绑定变量的情形下,不论是解析次数,闩使用的数量,队列,分配的内存,库缓存,行缓存远远高于绑定
  • 变量的情况。因此尽可能的使用绑定变量避免硬解析产生所需的额外的系统资源。
  • 绑定变量的优点
  • 减少SQL语句的硬解析,从而减少因硬解析产生的额外开销(CPU,Shared pool,latch)。其次提高编程效率,减少数据库的访问次数。
  • 绑定变量的缺点
  •  优化器就会忽略直方图的信息,在生成执行计划的时候可能不够优化。SQL优化相对比较困难

 

六、总结


 1.尽可能的避免硬解析,因为硬解析需要更多的CPU资源,闩等。

 2.cursor_sharing参数应权衡利弊,需要考虑使用similar与force带来的影响。

 3.尽可能的使用绑定变量来避免硬解析。 

 

Thanks and Regards

参考:乐沙弥大神 - http://blog.csdn.net/leshami/article/details/6195483

参考:乐沙弥大神 - http://10.61.208.50:15871/cgi-bin/blockpage.cgi?ws-session=18446744072512592920

参考:乐沙弥大神 - http://czmmiao.iteye.com/category/143940

ERP技术讨论群: 288307890
技术交流,技术讨论,欢迎加入
Technology Blog Created By Oracle ERP - 鲍新建
相关文章
|
2月前
|
负载均衡 Oracle 网络协议
Oracle中TAF与SCANIP全面解析
通过本文的解析,读者可以清晰地理解Oracle中TAF与SCAN IP的概念、工作原理及其在实际应用中的优势和局限性。TAF通过自动故障转移提升了会话的高可用性,而SCAN则通过简化客户端连接和负载均衡提升了集群的可管理性和扩展性。这两种技术在现代企业数据库架构中扮演着重要角色,能够显著提高系统的稳定性和可用性。
107 6
|
3月前
|
监控 Oracle 关系型数据库
Oracle数据库性能优化
【10月更文挑战第16天】Oracle数据库性能优化是
44 1
|
3月前
|
SQL 监控 Oracle
Oracle SQL性能优化全面指南
在数据库管理领域,Oracle SQL性能优化是确保数据库高效运行和数据查询速度的关键
|
3月前
|
缓存 前端开发 JavaScript
Webpack技术深度解析:模块打包与性能优化
【10月更文挑战第13天】Webpack技术深度解析:模块打包与性能优化
|
5月前
|
JavaScript 前端开发 算法
【Vue秘籍揭秘】:掌握这一个技巧,让你的列表渲染速度飙升!——深度解析`key`属性如何成为性能优化的秘密武器
【8月更文挑战第20天】Vue.js是一款流行前端框架,通过简洁API和高效虚拟DOM更新机制简化响应式Web界面开发。其中,`key`属性在列表渲染中至关重要。本文从`key`基本概念出发,解析其实现原理及最佳实践。使用`key`帮助Vue更准确地识别列表变动,优化DOM更新过程,确保组件状态正确维护,提升应用性能。通过示例展示有无`key`的区别,强调合理使用`key`的重要性。
75 3
|
5月前
|
监控 Oracle 关系型数据库
"深度剖析:Oracle SGA大小调整策略——从组件解析到动态优化,打造高效数据库性能"
【8月更文挑战第9天】在Oracle数据库性能优化中,系统全局区(SGA)的大小调整至关重要。SGA作为一组共享内存区域,直接影响数据库处理能力和响应速度。本文通过问答形式介绍SGA调整策略:包括SGA的组成(如数据缓冲区、共享池等),如何根据负载与物理内存确定初始大小,手动调整SGA的方法(如使用`ALTER SYSTEM`命令),以及利用自动内存管理(AMM)特性实现智能调整。调整过程中需注意监控与测试,确保稳定性和性能。
441 2
|
4月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
179 0
|
5月前
|
开发者 测试技术 Android开发
Xamarin 开发者的五大常见问题及解决方案:从环境搭建到性能优化,全面解析高效跨平台应用开发的技巧与代码实例
【8月更文挑战第31天】Xamarin 开发者常遇问题及解决方案覆盖环境搭建至应用发布全流程,助新手克服技术难关。首先需正确安装配置 Visual Studio 及 Xamarin 支持,设置 iOS/Android 测试环境。利用 Xamarin.Forms 和 XAML 实现高效跨平台开发,共享 UI 和业务逻辑代码。针对性能优化,采取减少 UI 更新、缓存计算结果等措施,复杂问题则借助 Xamarin Profiler 分析。
66 0
|
5月前
|
SQL 存储 数据库
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
103 2

推荐镜像

更多