Oracle硬解析和软解析的区别分析

一、摘要

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

SQL的执行过程

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

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

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

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

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

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

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

否则到步骤Step5。

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

Step6. 执行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"
      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
      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使用绑定变量来插入新记录
as
begin
for i in 1..10000
loop
execute immediate 'insert into tb_test values(:n)' using i;
end loop;
end;
/
Procedure created.
scott@ASMDB> create or replace procedure proc2 --创建存储过程proc2,未使用绑定变量,因此每一个SQL插入语句都会硬解析
as
begin
for i in 1..10000
loop
execute immediate 'insert into tb_test values('||i||')';
end loop;
end;
/
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.尽可能的使用绑定变量来避免硬解析。

(0)

相关推荐

  • Oracle硬解析和软解析的区别分析

    一.摘要 Oracle硬解析和软解析是我们经常遇到的问题,所以需要考虑何时产生软解析何时产生硬解析,如何判断 SQL的执行过程 当发布一条SQL或PL/SQL命令时,Oracle会自动寻找该命令是否存在于共享池中来决定对当前的语句使用硬解析或软解析. 通常情况下,SQL语句的执行过程如下: Step1. SQL代码的语法(语法的正确性)及语义检查(对象的存在性与权限). Step2. 将SQL代码的文本进行哈希得到哈希值. Step3. 如果共享池中存在相同的哈希值,则对这个命令进一步判断是否进

  • oracle常见故障类别及规划解析

    前言: 上一篇文章中我们了解了oracle分区索引的失效和重建代码示例的相关内容,接下来我们要看的内容是: 对任何数据库系统而言,对显而易见的故障,应当避免发生本文列出了Oracle常见的故障并给出了解决方案,同时列出了一些日常规划. 一.数据库高可用性的几个目标 MTBF(Mean-Time-Between-Failures) 平均失败时间,即数据库出现失败的频繁度,应尽可能增大该值            应对措施 RAC集群技术:位于多台计算机上的多个实例打开一个物理数据库,降低因一个或多实

  • oracle数据库导入导出命令解析

    Oracle数据导入导出imp/exp 功能:Oracle数据导入导出imp/exp就相当与oracle数据还原与备份. 大多情况都可以用Oracle数据导入导出完成数据的备份和还原(不会造成数据的丢失). Oracle有个好处,虽然你的电脑不是服务器,但是你装了oracle客户端,并建立了连接(通过Net Configuration Assistant添加正确的服务命名,其实你可以想成是客户端与服务器端 修了条路,然后数据就可以被拉过来了) 这样你可以把数据导出到本地,虽然可能服务器离你很远.

  • JSON解析和XML解析区别对比

    JSON解析和XML解析是较为普遍的两种解析方式,其中JSON解析的市场分额更大.本文系统的分析两种解析方式的区别,为更好地处理数据作准备.由于目前阶段主要是做移动开发,所以本文所描述的JSON解析和XML解析均是在安卓环境下进行测试. 首先要明确一点,数据解析是为了获取数据的每一个值,对于JSON数据而言类似于键值对的形式,对于XML而言是标签和值的形式.简单来说就是要在一个JSON数据或XML数据中利用键或标签找到对应值. 其次要了解一下两种数据的数据结构.JSON数据分为三种:对象类型.数

  • 解析C++各种变量及区别

    目录 一.分类 二.作用域 三.存储区域 四.总结 在日常开发中,我们经常使用变量,常量,像下面的代码: int ser_1; // 全局变量 const int ser_2; // 全局常量 static int ser_3; // 静态变量 void main(){ int serven_1; // 局部变量 const int serven_2; // 局部常量 static int serven_3; // 局部静态变量 func(serven_1); } void func(int p

  • vue数据监听解析Object.defineProperty与Proxy区别

    目录 前言 Object.defineProperty 与 Proxy 的区别 在使用上的差异 总结与思考 前言 总能深深感觉到自己能力有限,写这篇文章的目的纯粹是因为发现在实际工作中,和一些小伙伴交流时发现,虽然有些小伙伴大概知道 vue2 与 vue3 的区别,但并没有去进一步思考一些深一点的东西.尽管能力有限,但想着自己在起步时候的艰难,就想着分享一下自己的一些看法,虽然不一定有多深入,但能引起大家的一些思考也是好的. Object.defineProperty 与 Proxy 的区别 其

  • oracle中存储函数与存储过程的区别介绍

    在oracle中,函数和存储过程是经常使用到的,他们的语法中有很多相似的地方,可是也有它们的不同之处,这段时间刚学完函数与存储过程,来给自己做一个总结: 一:存储过程:简单来说就是有名字的pl/sql块. 语法结构: create or replace 存储过程名(参数列表) is --定义变量 begin --pl/sql end; 案例: create or replace procedure add_(a int,b int) is c int; begin c:=a+b; dbms_ou

  • iOS之数据解析之XML解析详解

    XML解析常见的两种方式:DOM解析和SAX解析 DOM解析 DOM:Document Object Model(文档对象类型).解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过遍历数结构可以检索任意XML节点,读取它的属性和值,而且通常情况下,可以借助XPath,直接查询XML节点. 进行DOM方式解析数据需要使用一个第三方的类GDataXMLNode GDataXMLNode是Google提供的开源XML解析类,对libxml2.tbd进行了Objective-C的

  • Oracle数据库中 call 和 exec的区别

    今天发现了一个小东西,觉得很有意思,查找了一些资料,跟大家分享一下: 在sqlplus中: 在第三方提供的工具(如:plsqldev) 总结: exec是sqlplus的命令,只能在sqlplus中使用. call是sql命令,任何工具都可以使用,call必须有括号,即例没有参数 call必须有括号,即例没有参数 idle> connect /as sysdba 已连接. sys@PO10> sys@PO10> create procedure p_test is 2 begin 3 n

  • Oracle过程与函数的区别分析

    Oracle过程和函数相信大家都比较了解,下面就为您详细介绍Oracle过程和函数二者之间的区别,希望可以让您对Oracle过程和函数有更深的认识. Oracle过程和函数都以编译后的形式存放在数据库中,函数可以没有参数也可以有多个参数并有一个返回值.过程有零个或多个参数,没有返回值.函数和过程都可以通过参数列表接收或返回零个或多个值,函数和过程的主要区别不在于返回值,而在于他们的调用方式.Oracle过程是作为一个独立执行语句调用的: pay_involume(invoice_nbr,30,d

随机推荐