PLSQL_解析过程及硬解析和软解析的区别(案例)

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

2014-08-11 Created 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将进行几个步骤的处理过程:

2.1 解析

Step1:检查共享池中是否有之前解析相同的SQL语句后所存储的SQL文本、解析树和执行计划。

如果能从共享池的缓存库中找到之前解析过生成的执行计划,则SQL语句则不需要再次解析,便可以直接由库缓存得到之前所产生的执行计划,从而直接跳到绑定或执行阶段,这种解析称作软解析。

但是如果在共享池的库缓存中找不到对应的执行计划,则必须继续解析SQL、生成执行计划,这种解析称作硬解析

Step2:语法分析,分析SQL语句的语法是否符合规范,衡量语句中各表达式的意义

Step3:检查是否存在语义错误和权限。语义分析,检查语句中设计的所有数据库对象是否存在,且用户有相应的权限。

Step4:视图转换和表达式转换 将涉及视图的查询语句转换为相应的对基表查询语句。将复杂表达式转化较为简单的等效连接表达式。

Step5:决定最佳执行计划。优化器会生成多个执行计划,在按统计信息带入,找出执行成本最小的执行计划,作为执行此SQL语句的执行计划

Step6:将SQL文本、解析树、执行计划缓存到库缓存,存放地址以及SQL语句的哈希值。

2.2 绑定

如果SQL语句中使用了绑定变量,扫描绑定变量的声明,给绑定变量赋值。则此时将变量值带入执行计划。

2.3 执行

此阶段按照执行计划执行SQL,产生执行结果。不同类型的SQL语句,执行过程也不同。

(1). SELECT查询

检查所需的数据块是否已经在缓冲区缓存中,如果已经在缓冲区缓存中,直接读取器内容即可。

这种读取方式称为逻辑读取。如果所需数据不在缓冲区缓存中,则服务器进程需要先扫描数据块,读取相应数据块到缓冲区缓存,这种读取方式称为物理读。和逻辑读相比较,它更加耗费CPU和IO资源。

(2). 修改操作(INSERT、UPDATE、DELETE)

Step 1:检查所需的数据库是否已经被读取到缓冲区缓存中。如果已经存在缓冲区缓存,则执行Step 3

Step 2:若所需的数据库并不在缓冲区缓存中,则服务器将数据块从数据文件读取到缓冲区缓存中

Step 3:对想要修改的表取得的数据行锁定(Row Exclusive Lock),之后对所需要修改的数据行取得独占锁

Step 4:将撤销数据的Redo记录复制到日志缓冲区,产生数据行的撤销数据,将数据行修改的Redo记录复制到日志缓冲区,修改数据行。

Step 5: 产生数据修改的撤销数据

Step 6:复制数据修改的Redo记录到日志缓冲区

Step 7:修改数据行的内容,如果之前的缓冲为干净缓冲,则此时将变为脏缓冲。

2.4 提取

提取只有SELECT查询语句才有的步骤。获取查询的记录行,必要的时候对查询结果排序。

 

3. 简而言之

Step1. 语法检查(syntax check)

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

Step2. 语义检查(semantic check)

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

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

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

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

 

4. 总结

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

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

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

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

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

  创建解析树、生成执行计划对于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

参考:潇湘隐者 http://www.cnblogs.com/kerrycode/p/3356845.html

ERP技术讨论群: 288307890
技术交流,技术讨论,欢迎加入
Technology Blog Created By Oracle ERP - 鲍新建
相关文章
|
20天前
|
存储 运维 安全
SaaS多租户和单租户的区别解析
SaaS多租户的系统维护成本低,多租户系统在升级时,只需要更新一次,维护人员不需要对每个用户更新,节省了很大的运维成本,这对于所有客户都在做同样事情的系统来说是很有用的。
39 3
|
2月前
|
前端开发 UED 开发者
颠覆你的前端知识:防抖与节流的区别及实战解析!
【8月更文挑战第23天】在Web前端开发中,处理用户界面交互产生的事件可能会影响性能。为此,我们有两种优化方法:防抖(debounce)和节流(throttle)。防抖确保函数仅在事件停止触发一段时间后执行一次,适用于如搜索自动补全场景。而节流则确保函数按固定时间间隔执行,不管用户操作频率如何。本篇技术博客将深入解析两者差异并提供示例代码,帮助开发者更好地理解和应用这些技巧以提升应用性能和用户体验。
64 0
|
1月前
|
缓存 网络协议 Linux
DNS解析工具使用案例
关于如何在Windows和Linux操作系统下使用DNS解析工具的案例,包括查看和清空DNS缓存、使用whois查询工具以及安装和使用dig工具进行DNS记录查询。
19 2
DNS解析工具使用案例
|
2月前
|
机器学习/深度学习 算法 数据库
阿里云服务器架构区别解析:从X86计算、Arm计算到高性能计算架构的区别参考
在我们选择阿里云服务器的架构时,选择合适的云服务器架构对于提升业务效率、保障业务稳定至关重要。阿里云提供了多样化的云服务器架构选择,包括X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器以及高性能计算等。本文将深入解析这些架构的特点、优势及适用场景,以供参考和选择。
阿里云服务器架构区别解析:从X86计算、Arm计算到高性能计算架构的区别参考
|
2月前
|
人工智能 PyTorch 算法框架/工具
Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
【8月更文挑战第6天】Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
|
5天前
|
存储 缓存 NoSQL
Redis 过期删除策略与内存淘汰策略的区别及常用命令解析
Redis 过期删除策略与内存淘汰策略的区别及常用命令解析
13 0
|
28天前
|
定位技术 网络虚拟化 数据中心
VLAN与VXLAN技术解析:仅一字之差的深远区别
通过深入了解VLAN与VXLAN的技术细节和应用场景,网络工程师可以根据具体需求选择最合适的技术来优化网络架构。对于现代网络环境,尤其是大规模和多变的网络结构,理解并合理运用这些技术是提高网络效率和安全性的关键。
38 1
|
2月前
|
JavaScript 前端开发 UED
Javaweb之javascript的小案例的详细解析
通过上述步骤,我们得到了一个动态更新的实时时钟,这个简单的JavaScript案例展示了定时器的使用方法,并讲解了如何处理日期和时间。这个案例说明了JavaScript在网页中添加动态内容与交互的能力。对于涉足JavaWeb开发的学习者来说,理解和运用这些基础知识非常重要。
36 11
|
1月前
|
弹性计算 开发框架 数据可视化
阿里云虚拟主机和云服务器有什么区别?多角度全解析对比
阿里云虚拟主机与云服务器ECS的主要区别在于权限与灵活性。虚拟主机简化了网站搭建流程,预装常用环境,适合初级用户快速建站;而云服务器提供全面控制权,支持多样化的应用场景,如APP后端、大数据处理等,更适合具备技术能力的用户。尽管虚拟主机在价格上通常更优惠,但随着云服务器价格的下降,其性价比已超越虚拟主机,成为更具吸引力的选择。
|
2月前
|
开发者
告别繁琐代码,JSF标签库带你走进高效开发的新时代!
【8月更文挑战第31天】JSF(JavaServer Faces)标准标签库为页面开发提供了大量组件标签,如`<h:inputText>`、`<h:dataTable>`等,简化代码、提升效率并确保稳定性。本文通过示例展示如何使用这些标签实现常见功能,如创建登录表单和展示数据列表,帮助开发者更高效地进行Web应用开发。
32 0

热门文章

最新文章

推荐镜像

更多
下一篇
无影云桌面