• oracle-绑定变量学习笔记(未完待续)




    --定义变量
    SQL> var a number;

    --给绑定变量赋值
    SQL> exec :a :=123;

    PL/SQL procedure successfully completed.

    --使用该绑定变量
    SQL> select * from test where n1= :a;

            N1
    ----------
           123


    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1357081020     --记住 执行计划的id

    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |     1 |     5 |    69   (2)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST |     1 |     5 |    69   (2)| 00:00:01 |
    --------------------------------------------------------------------------

    Predicate Information (identified by operation id):
    ---------------------------------------------------

       1 - filter("N1"=TO_NUMBER(:A))


    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
            191  consistent gets
              0  physical reads
              0  redo size
            521  bytes sent via SQL*Net to client
            523  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed

    --再次给绑定变量赋值
    SQL> exec :a :=1234;

    PL/SQL procedure successfully completed.

    --使用该绑定变量
    SQL> select * from test where n1= :a;

            N1
    ----------
          1234


    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1357081020   传给绑定变量的值 变了,但是依然采用原先的执行计划

    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |     1 |     5 |    69   (2)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST |     1 |     5 |    69   (2)| 00:00:01 |
    --------------------------------------------------------------------------

    Predicate Information (identified by operation id):
    ---------------------------------------------------

       1 - filter("N1"=TO_NUMBER(:A))


    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
            191  consistent gets
              0  physical reads
              0  redo size
            521  bytes sent via SQL*Net to client
            523  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed
    ----------------------------------------------------------------------------------------------------------

    在ORACLE中,使用绑定变量,可以降低硬解析,通常可以提高系统的性能(注意,是通常,不是任何情况下)。

           以表tabletest为例,我们来看看如何使用绑定变量,tabletest的表结构为

       Create table tabletest(   

    field1 number(10),

           field2 number(10),

           field3 number(10),

           field4 number(10),

           field5 number(10));

            绑定变量可以理解为一个占位符 ,例如:

    declare

        i number;

        j number;

        sqlstr varchar2(200);

    begin

        i:=1;

        j:=2; 

        sqlstr:='insert into tabletest (field1,field2,field3,field4,field5)    values(:x,:x,:y,:x,:x)';
          execute immediate sqlstr using i,i,j,i,i;

    end;

    这样的一段代码中,使用i,i,j,i,i来对应:x,:x,:y,:x,:x。这段代码是正确的,但如果以为sqlstr中只有:x,:y这两个绑定变量,而把语句execute immediate sqlstr using i,i,j,i,i; 改为execute immediate sqlstr using i,j; 就会在运行中出现绑定变量数量不够的错误。

    上面的正确代码执行完后,插入的记录从field1到field5的数据应该是1,1,2,1,1。

    如果我们把execute immediate sqlstr using i,i,j,i,i; 改成execute immediate sqlstr using i,j,j,i,i; 执行之后,察看插入的记录,就会发现插入的记录是1,2,2,1,1

    从上面可以看出,绑定变量只是起到占位的作用,同名的绑定变量并不意味着在它们是同样的,在传递时要考虑的是传递的值与绑定变量出现顺序的对位,而不是绑定变量的名称。

    ORACLE系统本身是能够对变量做绑定的,例如下面的代码:

    declare

        i number;

    begin

      for i in 1..1000 loop

          insert into tabletest (i,i+1,i*1,i*2,i-1)

      end loop;

    end;

    这段代码是不需要使用绑定变量的方法来提高效率的,ORACLE会自动将其中的变量绑定。

    我们可以这样理解:这段代码执行了1000次的 insert into 测试表 (i,i+1,i*1,i*2,i-1) 语句,每次发出去的语句都是一样的。

    如果把这段代码改成如下:

    declare

        i number;

        sqlstr varchar2(200);

    begin

      for i in 1..1000 loop

          sqlstr:='insert into tabletest ('||to_char(i)||','||to_char(i)||'+1,'||to_char(i)||'*1,'||to_char(i)||'*2,'||to_char(i)||'-1) ';

          execute immediate sqlstr;

      end loop;

    end;

    这段代码同样是执行了1000条insert语句,但是每一条语句都是不同的,因此ORACLE会把每条语句硬解析一次,其效率就比前面那段就低得多了。

    如果要提高效率,不妨使用绑定变量将循环中的语句改为

    sqlstr:='insert into 测试表 (:i,:i+1,:i*1,:i*2,:i-1) ';

          execute immediate sqlstr using i,i,i,i,i;

    这样执行的效率就高得多了。

        

    我曾试着使用绑定变量来代替表名、过程名、字段名等,结果是语句错误,结论就是绑定变量不能当作嵌入的字符串来使用,只能当作语句中的变量来用。

    从效率来看,由于oracle10G放弃了RBO,全面引入CBO,因此,在10G中使用绑定变量效率的提升比9i中更为明显。

    最后,前面说到绑定变量是在通常情况下能提升效率,那哪些是不通常的情况呢?

    答案是:在字段(包括字段集)建有索引,且字段(集)的集的势非常大(也就是有个值在字段中出现的比例特别的大)的情况下,使用绑定变量可能会导致查询计划错误,因而会使查询效率非常低。这种情况最好不要使用绑定变量。

    3. TOM大师的书本上的 实例

    绑定变量-变更前

     declare   
        type rc is ref cursor;
        l_rc rc;
        l_dummy all_objects.object_name%type;
        l_start number default dbms_utility.get_time;
        begin
         for i in 1..1000 loop
         open l_rc for
       'select object_name from all_objects where object_id='||i;
       fetch l_rc into l_dummy;
       close l_rc;
       end loop;
       dbms_output.put_line(round((dbms_utility.get_time-l_start)/100,2)||'seconds...');
       end;
      /

     绑定变量-变更后

    declare
        type rc is ref cursor;
        l_rc rc;
        l_dummy all_objects.object_name%type;
        l_start number default dbms_utility.get_time;
        begin
         for i in 1..1000 loop
         open l_rc for
       'select object_name from all_objects where object_id=:x' using i;
       fetch l_rc into l_dummy;
       close l_rc;
       end loop;
       dbms_output.put_line(round((dbms_utility.get_time-l_start)/100,2)||'seconds...');
       end;
      /

    效果非常明显哦,谢谢大师

  • 相关阅读:
    centos7 安装prometheus node_exporter
    RMAN备份演练初级篇
    RMAN命令
    oracle数据库的归档模式
    oracle的会话(session)
    oracle的例程
    oracle热备份
    Oracle数据库归档模式的切换及其相关操作详解
    Oracle角色
    类名.class, class.forName(), getClass()区别
  • 原文地址:https://www.cnblogs.com/iyoume2008/p/5195977.html
Copyright © 2020-2023  润新知