基于Oracle的SQL优化--学习(十)

Oracle里的Cursor

        绑定变量( Bind variable )是一种特殊类型的变量,它又被称为占位符( Placeholder ) ,绑定变量通常出现在目标 SQL 的 SQL 文本中,用于替换 SQL 文本中的 where 条件或者 values 子句(适用于 INSERT语句)中的具体愉入值。 oracle 数据库中绑定变量的使用语法是“ : variable_name " ,即用冒号和自定义变量名称的组合来转换目标 SQL SQL 文本中的具体输入值,这里自定义的变量名称 variable _ name 可以是字母、数字或字母与数字的组合,例如原目标 SQL 为“ select ename from emp where empno =7369 " ,该 SQL 中的具体输入位是 7369 . 如果这里用绑定变最(假设是 x )来转换上述具体输入值 7369 的话,则转换后的等价改写形式就足“select ename from emp where empno = : x " .

绑定变量的作用

         绑定变量的最大的作用是可以有效地降低系统硬解析的数量。

绑定变量的典型用法

        PL/SQL中的绑定变量的典型用法

    标准语法为:execute immediate [带 绑定变量的目标SQL] using [对应绑定变量的具体输入值];

    在PL/SQL代码中给绑定变最从仇的关键字是“ using " ,目标 SQL 中有几个绑定变最.关键字“ using " 后就需要跟几个具体的输入值(各愉入位之间以逗号分隔),这一点与之前介绍的在 SQLPLUS 中直接用“ exec " 给 SQL 语句中的绑定变量赋值有区别。

    对于上述这种使用绑定变量的方式,关健字‘ using ’后传入的绑定变,具体输入值只与对应绑定变里在目标 SOL 中所处的位置有关,而与其名称无关,这意味着只要目标 SQL 中绑定变量所处的位置不同,它们所对应的绑定变量名称是可以相同的。

    动态SQL也可以使用绑定变量,关键字“returning”可以和带绑定变量的目标SQL连用,其目的是把受该SQL 影响的行记录的对应字段取出来。

    可以简单地将 PL/SQL看作 Orade 数据库中专门用来处理 PL/SQL代码中除 SQL语句之外所有到余部分的子系统,而 SQL则是 Orade 数据库中专门用来处理 SQL语句的子系统.这里的 PL/SQL引擎和 SQL 引擎上下文切换就是指它们之间的交互.PL/SQL中的批量绑定的优势在于它是一次处理一批数据.而不是常规方式那样一次只处理一条致据,所以它能够有效减少 PL/SQL引擎SQL上下文切换的次数。

绑定变量的使用原则和最佳实践

         对于绑定变量,推荐的使用原则为:依据应用系统的类型来决定是否使用绑定变,具体来说就是:.
    1、对于 OLAP/DSS 类型的应用系统,可以不使用绑定变量。
    2、对于 OLTP类型的应用系统,在 SQL 语句中一定要使用绑定变量 ,并且最好是使用批量绑定,即尽可能在前台代码和后台 PL/SQL代码中都使用批量绑定
    3、对干 OLAPOLTP混合型的应用系统,如果有循环,不管这个循环是在前台代码还是在后台 PL/SQL代码中.循环内部的 SQL语句一定要使用绑定变量并且最好是使用批量绑定至于循环外部的 SQL 语句,可以不使用绑定变量。

绑定变量的个数不宜太多

         目标 SQL 的 SQL 文本中的绑定变量个数不宜太多,否则可能会导致目标 SQL 总的执行时间大幅度增长。增长的时间主要耗费在执行目标 SQL 时对每一个绑定变量都用其实际的值来替换(这个过程就是所谓的绑定变量值替换),目标 SQL 的 SQL 文本中的绑定变量的个数越多,这个替换过程所耗费的时间就越长,该 sQL 总的执行时间也就越长。

如何得到已执行的目标SQL中绑定变量的值

         查询视图 V $ SQL_BIND _ CAPTURE 。如果 V $ SQL_BIND _ CAPTURE 中查不到,那么有可能对应的 Shared Cursor 已经被 age out 出 Shared PooI了 ,这时候可以尝试去 AWR Repository 相关的数据字典表 DBA_HIST_SQLSTAT或 DBA_HIST_SQLBIND 中查询。当 Orade 解析和执行含有绑定变量的目标 SQL 时,如果满足如下两个条件之一,则该 SQL 中的绑定变量的具体输入值就会被 Oracle 捕获,并可通过视图 V $ SQL_BIND _ CAPTURE查询。
    (1)当含有绑定变量的目标 SQL 以硬解析的方式被执行时。
    (2)当含有绑定变量的目标 SQL 以软解析/软软解析的方式重复执行时,该 SQL 中的绑定变量的具体输入值也可能会被 Oracle 捕获,只不过默认情况下这种捕获操作 Oracle 至少得间隔 15 分钟才会做一次。也就是说当目标 SQL 以软解析/软软解析的方式重复执行时,本次捕获操作和上次捕获操作的时间间隔在默认情况下至少得间隔巧分钟。之所以间隔15分钟,是因为这可以避免频繁捕获而给系统性能带来的负面影响。我们当然希望目标 SQL 每次执行时其绑定变量输入值都被 Oracle 捕获,但这样一来会影响系统性能,二来也没必要(绑定变量窥探在默认情况下己被开启,所以默认情况下对于同一个反复执行的目标 SQL 而言,没必要每次执行时都捕获其绑定变量输入值)。
      Oracle 只会捕获那些位于目标 SQL 的 where 条件中的绑定变量的具体输入值,而对于那些使用了绑定变量的 INSERT 语句,不管该 INSERT 语句是否是以硬解析的方式执行, Oracle 始终不会捕获其 values 子句中对应绑定变量的具体输入值。

Oracle里的游标共享

     游标共享( Cursor Sharing )是指Shared Cursor 间的共享,说白了就是重用存储在 Child Cursor 中的解析树和执行计划而不用从头开始硬解析。

    游标共享对于应用系统在数据库端的性能和可扩展性是有至关重要的影响的,因为如果不能重用解析树和执行计划,就意味着同一类型的 SQL 在并发地被不同用户反复执行时每次都会用硬解析(这里“同一类型”的 SQL 是指除 SQL 文本中对应的输入值不同外,其他部分都一模一样的目标 SQL )。
    常规游标共享

    当开启了常规游标共享后, Oracle 在实际解析目标 SQL 之前,会先用系统产生的绑定变量来替换目标 SQL 的 SQL 文本中 where 条件或者 values 子句(适用于 INSERT 语句)中的具体输入值,这样替换后实际执行的 SQL 就已经是使用了绑定变量的改写后的等价 SQL ,同时因为这个替换过程是 Oracle 帮你做的,所以常规游标共享就可以做到既有效降低系统硬解析的数量又对应用透明。

    Oracle数据库中的常规游标共享受参数 CURSOR_SHARING 的控制,其值可以被设置为 EXACT 、 SIMILAR 或 FORCE ,它们各自的含义为如下所示。 

    (1) EXACT 是CURSOR_SHARING的默认值,当CURSOR_SHARING的值为 EXACT 时, Oracle 不会用系统产生的绑定变量来替换目标 SQL 的 SQL 文本中 where 条件或者 values 子句(适用于 INSERT 语句)中的具体输入值。

    (2)当 CURSOR _ SHARING 的值为 sIMILAR 时, Oracle 会用系统产生的绑定变量来替换目标

SQLSQL文本中 where 条件或者values子句(适用于 INSERT 语句)中的具体输入值,但这里替换归替换,替换后同一类型的 SQL 在并发地被不同的用户反复执行时是否能重用解析树和执行计划却是不一定的。因为当CURSOR _ SHARING 的值设为 SIMILAR 后, Oracle 只会对那些它认为是安全的谓词条件在替换后重用解析树和执行计划,对于它认为的不安全的谓词条件,即便用系统产生的绑定变量替换后的 SQL 文本是一模一样的,对于每一个不同的输入值, Oracle 都会执行一次硬解析,即此时会出现一个 Parent Cursor下挂一堆 Child Cursor 的现象,而这些Child Cursor中存储的解析树和执行计划很可能是一样的。

   (3) FORCE 和 SIMILAR 一样,当 CURSOR _ SHARING 的值为 FORCE 时, oracle 也会用系统产生的绑定变量来替换目标 SQL 的 SQL 文本中 where 条件或者 values 子句(适用于 INSERT 语句)中的具体输入值。但和 SIMILAR 不同的是,不管是“安全的谓词条件”还是“不安全的谓词条件”,当 CURSOR SHARING 的值为 FORCE 时,替换后同一类型的 SQL 总是会无条件地重用之前硬解析时的解析树和执行计划(注意,因为自适应游标共享的引入,这种行为不再适用于 Oracle 119 及其后续的版本)。
    总结来看SIMILAR 是一个即将过时的值,它有太多的副作用,无论什么时候都不要将CURSOR _ SHARING 的值设为 SIMILAR 。,如果想在不改一行应用代码的情况下,使那些仅仅是 SQL 文本中的 where 条件或者 values 子句(适用于 INSERT 语句)中的具体输入值不同的目标 SQL 共享解析树和执行计划,以达到有效降低系统硬解析数量的目的,那就将 CURSOR SHARING 的值设成 FORCE 吧,虽然这不是最理想的方案(最理想的方案当然还是修改应用的代码,在 SQL 语句里使用绑定变量,并且尽可能使用批量绑定),但这也许是最省事的方案。


         





你可能感兴趣的:(Oracle)