zoukankan      html  css  js  c++  java
  • Oracle SQL的硬解析和软解析

    我们都知道在Oracle中每条SQL语句在执行之前都需要经过解析,这里面又分为软解析和硬解析。在Oracle中存在两种类型的SQL语句,一类为 DDL语句(数据定义语言),他们是从来不会共享使用的,也就是每次执行都需要进行硬解析。还有一类就是DML语句(数据操纵语言),他们会根据情况选择要么进行硬解析,要么进行软解析。

     

    DML:INSERT,UPDATE,DELETE,SELECT

    DDL:CREATE,DROP,ALTER

     

     

    一.  SQL 解析过程

     

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

        1、语法检查(syntax check): 检查此sql的拼写是否语法。

        2、语义检查(semantic check): 诸如检查sql语句中的访问对象是否存在及该用户是否具备相应的权限。

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

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

     

     

     

     

     

    二. 解析过程详解

     

    2.1  语法检测

    判断一条SQL语句的语法是否符合SQL的规范,比如执行:

    SQL> selet * from emp;

    我们就可以看出由于Select关键字少了一个“c”,这条语句就无法通过语法检验的步骤了。

     

     

     

    2.2 语义检查

    语法正确的SQL语句在解析的第二个步骤就是判断该SQL语句所访问的表及列是否准确?用户是否有权限访问或更改相应的表或列? 比如如下语句:

    SQL> select * from emp;

    select * from emp

    *

    ERROR at line 1:

    ORA-00942: table or view does not exist

    由于查询用户没有可供访问的emp对象,因此该SQL语句无法通过语义检查。

     

     

     

    2.3 解析(Parse)

     

      2.3.1 Parse主要分为三种:

        1、Hard Parse (硬解析)

        2、Soft Parse (软解析)

        3、Soft Soft Parse(好像有些资料中并没有将这个算在其中)

     

       Hard Parse: 就是上面提到的对提交的Sql完全重新从头进行解析(当在Shared Pool中找不到时候将会进行此操作),总共有一下5个执行步骤:

        1:语法分析

        2:权限与对象检查

        3: 在共享池中检查是否有完全相同的之前完全解析好的. 如果存在,直接跳过4和5,运行Sql, 此时算soft parse.

        4:选择执行计划

        5:产生执行计划

     

    注:创建解析树、生成执行计划对于sql的执行来说是开销昂贵的动作,所以,应当极力避免硬解析,尽量使用软解析。这就是在很多项目中,倡导开发设计人员对功能相同的代码要努力保持代码的一致性,以及要在程序中多使用绑定变量的原因。

     

    Soft Parse: 就如果是在Shared Pool中找到了与之完全相同的Sql解析好的结果后会跳过Hard Parse中的后面的两个步骤。

     

        Soft Soft Parse: 实际上是当设置了session_cursor_cache这个参数之后,Cursor被直接Cache在当前Session的PGA中的,在解析的时候只需要对其语法分析、权限对象分析之后就可以转到PGA中查找了,如果发现完全相同的Cursor,就可以直接去取结果了,也就就是实现了 Soft Soft Parse.

     

     

     

     

    2.3.2 解析的步骤可以分为两个步骤:

     

    1) 验证SQL语句是否完全一致。

    在这个步骤中,Oracle将会对传递进来的SQL语句使用HASH函数运算得出HASH值,再与共享池中现有语句的HASH值进行比较看是否一一对应。现有数据库中SQL语句的HASH值我们可以通过访问v$sql、v$sqlarea、v$sqltext等数据字典中的HASH_VALUE列查询得出。

    如果SQL语句的HASH值一致,那么ORACLE事实上还需要对SQL语句的语义进行再次检测,以决定是否一致。那么为什么Oracle需要再次对语句文本进行检测呢?不是SQL语句的HASH值已经对应上了?事实上就算是SQL语句的HASH值已经对应上了,并不能说明这两条SQL语句就已经可以共享了。

     

    例如:假如用户SYS有自己的一张表EMP,他要执行查询语句:select * from emp; 用户SYSTEM也有一张EMP表,同样要查询select * from emp;这样他们两条语句在文本上是一模一样的,他们的HASH值也会一样,但是由于涉及到查询的相关表不一样,他们事实上是无法共享的. 

     

    SQL> conn / as sysdba

    已连接。

    SQL> show user

    USER 为 "SYS"

    SQL>  create table emp ( x int ) ;

    表已创建。

    SQL> select * from emp;

    未选定行

    SQL> conn system/admin;

    已连接。

    SQL>  create table emp ( x int );

    表已创建。

    SQL> select * from emp;

    未选定行

    SQL> select address,hash_value, executions, sql_text from v$sql where upper(sql_text) like 'SELECT * FROM EMP%';

    ADDRESS      HASH_VALUE  EXECUTIONS    SQL_TEXT                                                                

    -----------------------  ---------------------------------------------------------

    2769AE64    1745700775     1         select * from emp                                                                                                                         

    2769AE64    1745700775     1         select * from emp                                                    

    2 rows selected.

     

    从结果可以看到这2个查询的语句文本和HASH值都是一样的,但是由于查询的对象不同,是无法共享的,不同情况的语句还是需要硬解析的。因此在检查共享池共同SQL语句的时候,是需要根据具体情况而定的。

     

    可以进一步查询v$sql_shared_cursor以得知SQL为何不能共享的原因:

     

    SQL>select address,auth_check_mismatch,translation_mismatch,optimizer_mismatch 

    from v$sql_shared_cursor where address in ( 

    select address from v$sql where upper(sql_text) like 'SELECT * FROM EMP%' )  

     

    ADDRESS     A T O

    ----------------  ----- -- -- 

    2769AE64     N N N

    2769AE64     Y Y N

     

    TRANSLATION_MISMATCH 表示SQL游标涉及到的数据对象是不同的;

    AUTH_CHECK_MISMATCH 表示对同样一条SQL语句转换是不匹配的。

    optimizer_mismatch 表示会话的优化器环境是不同的。

     

     

     

    2)  验证SQL语句执行环境是否相同

     

    比如同样一条SQL语句,一个查询会话加了/*+ first_rows */的HINT,另外一个用户加/*+ all_rows */的HINT,他们就会产生不同的执行计划,尽管他们是查询同样的数据。

     

    通过如上检查以后,如果SQL语句是一致的,那么就会重用原有SQL语句的执行计划和优化方案,也就是我们通常所说的软解析。如果SQL语句没有找到同样的副本,那么就需要进行硬解析了。

     

    Oracle根据提交的SQL语句再查询相应的数据对象是否有统计信息。如果有统计信息的话,那么CBO将会使用这些统计信息产生所有可能的执行计划(可能多达成千上万个)和相应的Cost,最终选择Cost最低的那个执行计划。如果查询的数据对象无统计信息,则按RBO的默认规则选择相应的执行计划。这个步骤也是解析中最耗费资源的,因此我们应该极力避免硬解析的产生。至此,解析的步骤已经全部完成,Oracle将会根据解析产生的执行计划执行SQL语句和提取相应的数据。 

     

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

     

     

     

     

    三.  绑定变量 

        

        使用了Bind Var能提高性能主要是因为这样做可以尽量避免不必要的硬分析(Hard Parse)而节约了时间,同时节约了大量的CPU资源。

     

        当一个Client提交一条Sql给Oracle后,Oracle 首先会对其进行解析(Parse),然后将解析结果提交给优化器(Optimiser)来进行优化而取得Oracle认为的最优的Query Plan,然后再按照这个最优的Plan来执行这个Sql语句(当然在这之中如果只需要软解析的话会少部分步骤)。

     

    但是,当Oracle接到 Client提交的Sql后会首先在共享池(Shared Pool)里面去查找是否有之前已经解析好的与刚接到的这一个Sql完全相同的Sql(注意这里说的是完全相同,既要求语句上的字符级别的完全相同,又要求涉及的对象也必须完全相同)。当发现有相同的以后解析器就不再对新的Sql在此解析而直接用之前解析好的结果了。这里就节约了解析时间以及解析时候消耗的CPU资源。尤其是在OLTP中运行着的大量的短小Sql,效果就会比较明显了。因为一条两条Sql的时间可能不会有多少感觉,但是当量大了以后就会有比较明显的感觉了。

  • 相关阅读:
    OSG-提示“error reading file e:1.jpg file not handled”
    OSG-加载地球文件报0x00000005错误,提示error reading file simple.earth file not handled
    QT-找开工程后,最上方提示the code model could not parse an included file, which might lead to incorrect code completion and highlighting, for example.
    我的书《Unity3D动作游戏开发实战》出版了
    java中无符号类型的第三方库jOOU
    Windows批处理备份mysql数据
    使用 DevTools 时,通用Mapper经常会出现 class x.x.A cannot be cast to x.x.A
    Java版本,Java版本MongoDB驱动,驱动与MongoDB数据库,Spring之间的兼容性
    Jrebel本地激活方法
    wget下载指定网站目录下的所有内容
  • 原文地址:https://www.cnblogs.com/husam/p/6148635.html
Copyright © 2011-2022 走看看