`
liwenshui322
  • 浏览: 511958 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Oracle 游标与绑定变量

 
阅读更多

 

oracle执行SQL语句就是打开游标,解析游标,执行游标,关闭游标的过程。了解游标的这几个阶段,我们也就弄清楚了SQL执行过程,这是本文要介绍的第一个内容。另外,在java编程中,我们通常说要使用预处理的形式来写SQL语句(比如:select  * from table where A = ?),也就是绑定变量的形式。因为,这样效率高。那么,为什么使用绑定变量就比不使用绑定变量(比如:select * from table where A = '123')要效率高呢?这是本文要介绍的第二个内容。


        一. 游标的生命周期

       一条sql语句的执行过程,就是一个游标的生命周期。如下图所示:


     1. 打开游标:系统为这个游标分配一个内存结构。

        2. 解析游标:将一条SQL与这个游标关联。解析这条sql语句,将解析的结果加载到共享池中。

        3. 定义输出变量:如果这条SQL返回数据,先定义接收数据的变量。

        4. 定义输入变量:如果SQL语句使用了绑定变量,提供他们的值。

        5. 执行游标:执行SQL语句。

        6. 获取游标:如果SQL语句有返回数据,接收返回的数据。

        7. 关闭游标:释放第一步分配的内存,供其他游标使用,但是第二步解析的SQL结果(也就是共享游标)不会被释放,以期待被重新使用。


        我们可以通过一段PL/SQL代码来看一下游标的这几个步骤:      


  1. DECLARE  
  2.   l_ename emp.ename%TYPE := 'SCOTT';  
  3.   l_empno emp.empno%TYPE;  
  4.   l_cursor INTEGER;  
  5.   l_retval INTEGER;  
  6. BEGIN  
  7.   l_cursor := dbms_sql.open_cursor; /*打开游标*/  
  8.   dbms_sql.parse(l_cursor, 'SELECT empno FROM emp WHERE ename = :ename', 1); /*解析游标*/  
  9.   dbms_sql.define_column(l_cursor, 1, l_empno); /*定义输出变量*/  
  10.   dbms_sql.bind_variable(l_cursor, ':ename', l_ename); /*定义输入变量*/  
  11.   l_retval := dbms_sql.execute(l_cursor); /*执行游标*/  
  12.   IF dbms_sql.fetch_rows(l_cursor) > 0  /*获取游标*/  
  13.   THEN    
  14.     dbms_sql.column_value(l_cursor, 1, l_empno);  
  15.     dbms_output.put_line(l_empno);  
  16.   END IF;  
  17.   dbms_sql.close_cursor(l_cursor); /*关闭游标*/  
  18. END;  


 

        二. 游标的解析过程

       在游标的这几个过程中,我们唯一能影响的就是解析过程。解析过程的快与慢,与我们写的sql语句有直接关系。那么游标的解析过程(也就是SQL的解析过程)是怎样的呢?看下图:


       1. 包含VPD的约束条件检查:如果系统中使用了虚拟私有数据库,并且被解析的SQL语句中引用的某张表激活了它的话,安全策略生成的约束条件会被添加到where条件中(说实话,这个我也没看懂,先不管)

       2. 语法,语义以及访问权限检查:就是检查我们写的SQL写得对不对,引用的表是否存在等。

       3. 将父游标保存到库缓存:如果没有找到共享的父游标,就会在库缓存中缓存这个父游标。父游标保存的是这条SQL的文本信息,今后如果重新执行这条SQL语句,这个父游标是可以重用的。

       4. 逻辑优化与物理优化:生成这条SQL所有可能的执行计划,然后根据执行计划的开销,选择开销最小的一条执行计划。

       5. 将子游标保存到库缓存:上一步选择的最优执行计划信息和当前的执行环境,会当做子游标的信息保存到库缓存,并与父游标关联。


       总之,父游标保存的是SQL文本信息,今后可以被重用。子游标保存的是当前执行环境下所选择的这条SQL最优的执行计划,如果父游标被重用,执行环境没变,那么子游标也会被重用。

       当父游标和子游标都可重用,那么只需要执行前2步,此时对应的解析称为软解析。如果父游标与子游标都不可重用,所有的步骤都执行的时候,就是我们说的硬解析。因为硬解析里面的逻辑优化与物理优化是非常依赖cpu的操作,所以硬解析相对而言是比较耗时的。也就是我们为什么说要尽可能避免硬解析。


       三. 绑定变量优点

       绑定变量可以有效消除硬解析,我们执行如下一段SQL文本:


  1. DROP TABLE t;  
  2.   
  3. CREATE TABLE t (n NUMBER, v VARCHAR2(4000));  
  4.   
  5. ALTER SYSTEM FLUSH SHARED_POOL;  
  6.   
  7. VARIABLE n NUMBER  
  8. VARIABLE v VARCHAR2(32)  
  9.   
  10. EXECUTE :n := 1; :v := 'Helicon';  
  11.   
  12. INSERT INTO t (n, v) VALUES (:n, :v);  
  13.   
  14. EXECUTE :n := 2; :v := 'Trantor';  
  15.   
  16. INSERT INTO t (n, v) VALUES (:n, :v);  
  17.   
  18. EXECUTE :n := 3; :v := 'Kalgan';  
  19.   
  20. INSERT INTO t (n, v) VALUES (:n, :v);  
  21.   
  22. SELECT sql_id, child_number, executions  
  23. FROM v$sql  
  24. WHERE sql_text = 'INSERT INTO t (n, v) VALUES (:n, :v)';  
  25.   
  26. drop table t;  

        我们会发现最后一个select语句执行的结果如下图所示:


 

     说明对应这条insert语句只生成了一个父游标,只是这个父游标被执行了3次。也就是除开第一次插入的时候,我们进行了硬解析。接下来2次,我们都进行的是软解析。


       四. 绑定变量缺点

       影响oracle选择效率低下的执行计划。

       由于使用绑定变量,父游标和子游标都能共享重用(除开第一次硬解析,其他每次都是软解析)。子游标每次都重用(除开第一次),那么执行计划每一次都相同。假如子游标里面的执行计划确认进行的是全表扫描,因为第一次要查询这个表里面绝大部分数据,oracle认为执行全表扫描快。如果第二次只需要扫描很小一部分数据,执行索引扫描比较快的话。由于子游标重用,还执行的是全表扫描。我们可以看一个例子:

      执行如下一段SQL文本:


  1. VARIABLE id NUMBER  
  2. SET ECHO ON  
  3. ALTER SYSTEM FLUSH SHARED_POOL;  
  4. DROP TABLE t;  
  5. CREATE TABLE t   
  6. AS   
  7. SELECT rownum AS id, rpad('*',100,'*'AS pad   
  8. FROM dual  
  9. CONNECT BY level <= 1000;  
  10.   
  11. ALTER TABLE t ADD CONSTRAINT t_pk PRIMARY KEY (id);  
  12.   
  13. BEGIN  
  14.   dbms_stats.gather_table_stats(  
  15.     ownname          => user,   
  16.     tabname          => 't',   
  17.     estimate_percent => 100,   
  18.     method_opt       => 'for all columns size 1'  
  19.   );  
  20. END;  
  21. /  
  22.   
  23. EXECUTE :id := 990;  
  24. SELECT count(pad) FROM t WHERE id < :id;  
  25. SELECT * FROM table(dbms_xplan.display_cursor(NULLNULL'basic'));  
  26. EXECUTE :id := 10;  
  27. SELECT count(pad) FROM t WHERE id < :id;  
  28. SELECT * FROM table(dbms_xplan.display_cursor(NULLNULL'basic'));  

       我们发现当 id=10, 也就是查询非常小部分数据的时候,仍然执行的是全表扫描,如下图:


       

       五. 绑定变量使用场景

       什么时候应该使用绑定变量,什么时候又应该避免呢?

       我们可以看到,使用绑定变量主要是为了避免硬解析,也就是加快SQL的解析时间,但是有可能导致Oracle重用效率低下的执行计划。也就是延长SQL的执行时间。这个时候我们应该权衡,这条SQL是解析时间比较长还是执行时间。

       1. 如果一次只处理小部分数据,解析时间等于或者高于执行时间,那么建议使用绑定变量。

       2. 如果一次处理大批量数据,执行时间高于解析时间几个数量级,那么没必要使用绑定变量,加快那么一点解析时间微不足道。而且还有可能导致oracle重用效率低下的执行计划,大大影响SQL的执行速度。

  • 大小: 117.9 KB
  • 大小: 3.8 KB
  • 大小: 14.4 KB
  • 大小: 107.8 KB
分享到:
评论

相关推荐

    Oracle 游标的使用

    在Oracle 9i及其以后的版本中,还增加了使用BULK COLLECT子句批量绑定数据和使用CURSOR表达式实现嵌套游标的功能。本章将主要介绍如何使用显式游标进行多行数据的查询、游标FOR循环以及游标变量的使用,另外还将介绍...

    Oracle 从入门到精通视频教程(11G版本)(ppt)

    《Oracle 从入门到精通》中的视频教程和PPT资料。...使用绑定的方式连接Oracle 使用写代码的方式连接Oracle 第22章-在Java中连接Oracle JDBC与ODBC简介 Thin方式连接Oracle JDBC-ODBC桥连接Oracle

    Oracle11g从入门到精通2

    5.2.6 使用绑定变量 5.2.7 跟踪语句 5.3 设置SQL*Plus环境 5.3.1 SHOW命令 5.3.2 SET命令 5.4 SQL*Plus环境介绍 5.4.1 存储SQL*Plus环境 5.4.2 假脱机输出 5.4.3 联机帮助 5.5 使用SQL*Plus格式化...

    Oracle11g从入门到精通

    5.2.6 使用绑定变量 5.2.7 跟踪语句 5.3 设置SQL*Plus环境 5.3.1 SHOW命令 5.3.2 SET命令 5.4 SQL*Plus环境介绍 5.4.1 存储SQL*Plus环境 5.4.2 假脱机输出 5.4.3 联机帮助 5.5 使用SQL*Plus格式化查询结果 ...

    ORACLE11G宝典.rar 是光盘里面的内容,书太厚咧没法影印啊

     2.6.3 绑定变量  2.7自定义SQL*Plus环境  2.7.1 使用SHOW命令  2.7.2 使用SET命令  2.7.3 保存与定制SQL*Plus环境  2.8 格式化查询结果  2.8.1 格式化列  2.8.2 限制重复行  2.8.3 使用汇总行  ...

    Oracle.11g.从入门到精通 (2/2)

    5.2.6 使用绑定变量 5.2.7 跟踪语句 5.3 设置SQL*Plus环境 5.3.1 SHOW命令 5.3.2 SET命令 5.4 SQL*Plus环境介绍 5.4.1 存储SQL*Plus环境 5.4.2 假脱机输出 5.4.3 联机帮助 5.5 使用SQL*Plus格式化查询结果 5.5.1 ...

    Oracle.11g.从入门到精通 (1/2)

    5.2.6 使用绑定变量 5.2.7 跟踪语句 5.3 设置SQL*Plus环境 5.3.1 SHOW命令 5.3.2 SET命令 5.4 SQL*Plus环境介绍 5.4.1 存储SQL*Plus环境 5.4.2 假脱机输出 5.4.3 联机帮助 5.5 使用SQL*Plus格式化查询结果 5.5.1 ...

    jamdb_oracle:适用于Erlang的Oracle数据库驱动程序

    使用绑定变量。 调用存储过程。 调用存储的函数。 使用游标变量。 使用返回子句。 更新批处理。 行预取。 入门 % % Set connection options 1 &gt; Opts = [ { host , " jamdb-oracle-dev.erlangbureau.dp.ua ...

    精通Oracle.10g.PLSQL编程

    使用游标 9.1 显式游标 9.2 参数游标 9.3 使用游标更新或删除数据 9.4 游标FOR循环 9.5 使用游标变量 9.6 使用CURSOR表达式 9.7 习题 第10章 处理例外 10.1 例外简介 10.2 ...

    ORACLE SQL性能优化系列

    第一组的两个SQL语句是相同的(可以共享),而第二组中的两个语句是不同的(即使在运行时,赋于不同的绑定变量相同的值) a. select pin , name from people where pin = :blk1.pin; select pin , name from people ...

    sql总结.doc

    由于存储过程将应用程序绑定到数据库,因此使用存储过程封装业务逻辑将限制应用程序的可移植性。 (5)存储过程的应用场景 1.通常,复杂的业务逻辑需要多条 SQL 语句。这些语句要分别地从客户机发送到服务器,当客户...

    精通SQL 结构化查询语言详解

    17.4.1 显式游标与隐式游标 17.4.2 游标的属性  17.4.3 %TYPE、%ROWTYPE定义记录变量  17.4.4 参数化游标  17.4.5 游标中的循环  17.4.6 游标变量 17.5 小结  第18章 事务控制与并发处理 18.1 SQL...

    精通SQL--结构化查询语言详解

    17.4.1 显式游标与隐式游标 365 17.4.2 游标的属性 366 17.4.3 %type、%rowtype定义记录变量 367 17.4.4 参数化游标 368 17.4.5 游标中的循环 369 17.4.6 游标变量 371 17.5 小结 372 第18章 事务控制与并发...

    精通sql结构化查询语句

    以SQL Server为工具,讲解SQL语言的应用,提供了近500个曲型应用,读者可以随查随用,深入讲解SQL语言的各种查询语句,详细介绍数据库设计及管理,详细讲解存储过程、解发器和游标等知识,讲解了SQL语言在高级语言中...

    oracle+proc中文.pdf

    3.6.5 我能在 SQL 语句的任意位置使用绑定变量(也可理解为用户自定义变量或输入 宿主变量)吗?.................................................................................................................

    php网络开发完全手册

    4.2.7 变量检测函数isset与变量释放 4.2.7 函数unset 66 4.2.8 随机函数rand与srand 66 4.3 关于引用的解释 67 4.3.1 对变量的引用 67 4.3.2 对函数的引用 68 4.3.3 引用的释放 68 4.4 小结 69 第5章 PHP中类的应用 ...

    亮剑.NET深入体验与实战精要3

    2.6 公共变量与属性的区别 93 2.7 参数修饰符params、out和ref的区别 96 2.8 值类型和引用类型的区别 100 2.9 结构与类的区别 103 2.10 Dispose()和Close()、Finalize()的 区别 106 2.11 string和StringBuilder有...

    亮剑.NET深入体验与实战精要2

    2.6 公共变量与属性的区别 93 2.7 参数修饰符params、out和ref的区别 96 2.8 值类型和引用类型的区别 100 2.9 结构与类的区别 103 2.10 Dispose()和Close()、Finalize()的 区别 106 2.11 string和StringBuilder有...

    一个好用的数据库类

    在VC知识库第六期上面有一篇介绍"单独使用CRecordset"文章,可是上面的CRecordset打开方式只能使用CRecordset::forwardOnly,游标只能向前滚动,而且用这种方式,你根本无法从打开的记录集中获得本次查询得到了有...

Global site tag (gtag.js) - Google Analytics