`

Oracle绑定变量详解(原创)

 
阅读更多

绑定变量概述
oracle对SQL语句进行了概括和抽象,将SQL语句提炼为两部分,一部分是 SQL语句的静态部分,也就是SQL语句本身的关键词、所涉及的表名称以及表的列等。另一部分就是SQL语句的动态部分,也就是SQL语句中的值(即表里 的数据)。很明显的,整个数据库中所包含的对象数量是有限的,而其中所包含的数据则是无限的。而正是这无限的数据导致了SQL语句的千变万化,也就是说在 数据库运行的过程中,发生的所有SQL语句中,静态部分可以认为数量是有限的,而动态部分则是无限的。而实际上,动态部分对解析的影响相比静态部分对解析 的影响来说是微乎其微,也就是说通常情况下,对于相同的静态部分的SQL 语句来说,不同的动态部分所产生的解析结果(执行计划)基本都是一样的。这也就为oracle提高解析SQL语句的效率提供了方向。
oracle中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析,一种叫做软解析.
一个硬解析需要经解析,制定执行路径,优化访问计划等许多的步骤.硬解释不仅仅耗费大量的cpu,更重要的是会占据重要闩(latch)资源,严重的影响系统规模扩大(即限制了系统的并发行), 而且引起的问题不能通过增加内存条和cpu的数量来解决。之所以这样是因为闩是为了顺序访问以及修改一些内存区域而设置的,这些内存区域是不能被同时修改。

当一个sql语句提交后,oracle会首先检查一下共享缓冲池(shared pool)里有没有与之完全相同的语句,如果有的话只须执行软分析即可,否则就得进行硬分析。
当oracle在shared pool中查找相同的SQL语句的过程中,如果SQL语句使用了绑定变量(bind variable),那么就是比较SQL语句的静态部分,前面我们已经知道,静态部分是有限的,很容易就能够缓存在内存里,从而找到相同的SQL语句的概 率很高。如果没有使用绑定变量,则就是比较SQL语句的静态部分和动态部分,而动态部分的变化是无限的,因此这样的SQL语句很难被缓存在shared pool里。毕竟内存是有限的,不可能把所有的动态部分都缓存在shared pool里,即便能够缓存,管理这样一个无限大的shared pool也是不可能完成的任务。不使用绑定变量导致的直接结果就是,找到相同的SQL语句的概率很低,导致必须完整的解析SQL语句,也就导致消耗更多的资源。
事实上绑定变量只是起到占位的作用,同名的绑定变量并不意味着它们是相同的,在传递时要考虑的是传递的值与绑定变量出现顺序的对位,而不是绑定变量的名称。
注意:绑定变量不能当作嵌入的字符串来使用,只能当作语句中的变量来用。不能用绑定变量来代替表名、过程名、字段名等.
绑定变量的使用环境
由于在OLTP中,SQL语句大多是比较简单或者操作的结果集都很小。当一个表上创建了索引,那么这种极小结果集的操作使用索引最合适,并且几乎所有的SQL的执行计划的索引都会被选择,因为这种情况下,索引可能只需要扫描几个数据块就可以定位到数据,而全表扫描将会相当耗资源。 因此,这种情况下,即使每个用户的谓词条件不一样,执行计划也是一样的,就是都用索引来访问数据,基本不会出现全表扫描的情况。 在这种执行计划几乎唯一的情况下,使用绑定变量来代替谓词常量是合适的。
注意:如果系统中某些数据有倾斜的情况,对于这些数据的操作也不是于使用绑定变量,因为他会影响执行计划
在OLAP系统中,SQL的操作就复杂很多,OLAP数据库上大多数时候运行的一些报表SQL,这些SQL经常会用到聚合查询(如:group by),而且结果集也是非常庞大,在这种情况下,索引并不是必然的选择,甚至有时候全表扫描的性能会更优于索引,即使相同的SQL,如果谓词不同,执行计划都可能不同。
让Oracle对每条SQL做硬分析,确切的知道谓词条件的值,这对执行计划的选择至关重要,这样做的原因是为了得到一个最优的执行计划。 在OLAP系统中, 系统的资源基本上是用于做大的SQL查询 和查询比起来SQL解析消耗的资源显得微不足道 ,SQL硬分析的代价是可以忽略的。 因此让Oracle确切地知道谓词的数值至关重要,它直接决定了SQL执行计划的选择,所以在 OLAP系统完全没有必要绑定变量,那样很可能带来负面影响,比如导致SQL选择错误的执行,这个代价有时是灾难性的。
Bind Peeking是Oracle 9i中引入的新特性,它的作用就是在SQL语句硬分析的时候,查看一下当前SQL谓词的值,以便生成最佳的执行计划。而在oracle 9i之前的版本中,Oracle只根据统计信息来做出执行计划。要注意的是,Bind Peeking只发生在硬分析的时候,即SQL被第一次执行的时候,之后的变量将不会在做peeking。我们可以看出,Bind peeking并不能最终解决不同谓词导致选择不同执行计划的问题,它只能让SQL第一次执行的时候,执行计划选择更加准确,并不能帮助OLAP系统解决绑定变量导致执行计划选择错误的问题。这也是OLAP不应该使用绑定变量的一个原因。

实验示例
SQL> create table bind_a(id number,name varchar2(20));
Table created.
SQL> begin
  2   for i in 1..10000 loop
  3   if i <= 9900 then
  4     insert into bind_a values(i,'A');
  5   else
  6     insert into bind_a values(i,'DBA');
  7   end if;
  8   commit;
  9   end loop;
 10* end;
 /
SQL> create index BIND_A_IDX ON BIND_A(NAME);                       
Index created.
SQL> select TABLE_NAME,COLUMN_NAME,NUM_DISTINCT,NUM_BUCKETS,HISTOGRAM from DBA_TAB_COL_STATISTICS where table_name='BIND_A';
TABLE_NAME   COLUMN_N NUM_DISTINCT NUM_BUCKETS HISTOGRAM
------------ -------- ------------ ----------- --------------------
BIND_A       NAME                2           2 FREQUENCY
BIND_A       ID              10000          75 HEIGHT BALANCED
SQL> var t varchar2(10);
SQL> exec :t:='DBA';
SQL> select count(*) from bind_a where name= :t
  COUNT(*)
----------
       100

SQL>select sql_text,child_number,executions ,buffer_gets from v$sql where sql_text='select count(*) from bind_a where name= :t'
SQL_TEXT                                                    CHILD_NUMBER EXECUTIONS BUFFER_GETS
--------------------------------------------------------- ------------ ---------- -----------
select count(*) from bind_a where name= :t               
0         1                 3         
CHILD_NUMBER为0,执行了1次
SQL> select count(*) from bind_a where name= :t;
  COUNT(*)
----------
       100
SQL> select sql_text,child_number,executions ,buffer_gets from v$sql where sql_text='select count(*) from bind_a where name= :t'
  2  ;

SQL_TEXT                                                  CHILD_NUMBER EXECUTIONS BUFFER_GETS
--------------------------------------------------------- ------------ ---------- -----------
select count(*) from bind_a where name= :t                           0          2           6

CHILD_NUMBER为0,执行了2次
SQL> explain plan for select count(*) from bind_a where name= :t;
Explained.
SQL> select * from table(dbms_xplan.display)
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1309236542
------------------------------------------------------------------------------------
| Id  | Operation             | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |            |     1 |     3 |     6   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE       |            |     1 |     3 |            |          |
|*  2 |   INDEX FAST FULL SCAN| BIND_A_IDX |  5000 | 15000 |     6   (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
   2 - filter("NAME"=:T)
14 rows selected.
这里的由于DBA的值较少,故采用了
INDEX FAST FULL SCAN ,将name的值改为A
SQL> exec :t := 'A';
PL/SQL procedure successfully completed.
SQL> select count(*) from bind_a where name= :t;
  COUNT(*)
----------
      9900
SQL> select sql_text,child_number,executions ,buffer_gets from v$sql where sql_text='select count(*) from bind_a where name= :t';
SQL_TEXT                                                  CHILD_NUMBER EXECUTIONS BUFFER_GETS
--------------------------------------------------------- ------------ ---------- -----------
select count(*) from bind_a where name= :t                           0          3          25

--这个cursor执行3次,说明换了值之后,还是使用的这个cursor,child_number依旧为0。查看执行计划
SQL> explain plan for select count(*) from bind_a where name= :t;
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1309236542
------------------------------------------------------------------------------------
| Id  | Operation             | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |            |     1 |     3 |     6   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE       |            |     1 |     3 |            |          |
|*  2 |   INDEX FAST FULL SCAN| BIND_A_IDX |  5000 | 15000 |     6   (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
   2 - filter("NAME"=:T)
14 rows selected.

可以看到,由于bind peeking只发生在硬解析时,在已经生产了执行计划的情况下,bind peeking并不会帮助sql产生最优的执行计划,所以在10g中,如果数据存在严重倾斜或者在OLAP系统中不建议采用绑定变量。

为了解决上述问题,Oracle11g中引入了adaptive cursor sharing( 适应性游标共享) 、Bind-Sensitive Cursors、 Bind-Aware Cursors、和Cursor Merging 的新功能。详细的信息可以参考笔者的如下博客

http://czmmiao.iteye.com/blog/1905855

11g中虽然对绑定变量的使用进行了优化,感觉更加智能,但依据笔者的经验,在OLAP系统下,由于系统语句重复率低,解析占用的资源相对少的特点,使用绑定变量的意义不大。同时为了避免CBO时不时的“犯傻",建议在OLAP系统下少用,甚至不用绑定变量。而11g的这个特点可以说进一步加强了OLTP系统下绑定变量的使用性能。

 

参考至:《让Oracle跑得更快》谭怀远著
               http://blog.csdn.net/tianlesoftware/article/details/6591222
               http://www.dbanotes.net/database/top_bind_variables.html
               http://docs.oracle.com/cd/E11882_01/server.112/e16638/optimops.htm#PFGRF95174
               http://blog.csdn.net/tianlesoftware/article/details/6324243
               http://blog.csdn.net/tianlesoftware/article/details/5856430
本文原创,转载请注明出处、作者
如有错误,欢迎指正
邮箱:czmcj@163.com

1
0
分享到:
评论
1 楼 xly931 2016-04-25  
请站在东南方向,受我一拜

相关推荐

    Oracle DBA调优技术学习笔记

    Oracle 12c-优化 Hint详解.pdf Oracle 12c-优化 Oracle 索引技术.pdf Oracle 12c 执行计划.pdf ...Oracle 12c 使用绑定变量 VS 不使用绑定变量.pdf Oracle 12c 自动工作负载信息库AWR.pdf Oracle 12c 常用SQL.pdf

    oracle调试存储过程的过程详解

    oracle如果存储过程比较复杂,我们要定位到错误就比较困难,那么可以存储过程的调试功能 先按简单的存储过程做个例子,就是上次做的存储过程(proc_test) 1、先在数据库的procedures文件找到我们之前创建存储过程 ...

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

    《精通SQ:结构化查询语言详解》全面讲解SQL语言,提供317个典型应用,读者可以随查随用,针对SQL Server和Oracle进行讲解,很有代表性。 全书共包括大小实例317个,突出了速学速查的特色。《精通SQ:结构化查询语言...

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

    13.5.1 oracle中用户、资源、概要文件、模式的概念 269 13.5.2 oracle中的用户管理 269 13.5.3 oracle中的资源管理 274 13.5.4 oracle中的权限管理 277 13.5.5 oracle中的角色管理 278 第14章 完整性控制 281 ...

    IOCP_API(2.4)

    1. 连接oracle时,目录中不能有()字符,否则ADO是无法连接数据库的 修改: 2.1 去掉TCPChannel的BuildPacket函数,改成直接由OnRecv回调函数返回实际数据 去掉UDPChannel的Response函数,改成直接由内部处理 2.2 ...

    勤哲excel服务器2010教程

    17.1.2 将编号中的表单变量绑定到数据项 298 17.1.3 编号重用 299 17.2 树型选择 300 17.3 树型和列表的动态条件 305 17.4 列表和树形的组合 306 第18章、 工作流详解 309 18.1 任务执行人 309 18.2 工作流的分支与...

    php网络开发完全手册

    13.3.2 ORACLE 207 13.3.3 SYBASE 207 13.3.4 DB2 207 13.3.5 SQL Server 207 13.4 SQL语言简介 207 13.5 常见的数据库设计问题 208 13.6 关系型数据库的设计原则 209 13.6.1 第一范式(1NF) 209 13.6.2 第二范式...

    asp.net知识库

    Oracle中PL/SQL单行函数和组函数详解 mssql+oracle Oracle编程的编码规范及命名规则 Oracle数据库字典介绍 0RACLE的字段类型 事务 CMT DEMO(容器管理事务演示) 事务隔离性的一些基础知识 在组件之间实现事务和异步...

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

    1.3.6 变量的作用域 13 1.3.7 常量 16 1.3.8 流程控制 16 1.3.9 字符串常见操作 21 1.3.10 几个常用的数学函数 27 1.4 .NET的面向对象之门 27 1.4.1 继承——“子承父业” 28 1.4.2 委托——“任务书” 35 1.4.3 ...

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

    1.3.6 变量的作用域 13 1.3.7 常量 16 1.3.8 流程控制 16 1.3.9 字符串常见操作 21 1.3.10 几个常用的数学函数 27 1.4 .NET的面向对象之门 27 1.4.1 继承——“子承父业” 28 1.4.2 委托——“任务书” 35 1.4.3 ...

    整理后java开发全套达内学习笔记(含练习)

    ORACLE_SID=oral10g\ --变局部变量 export ORACLE_SID --变全局变量 unset ORACLE_SID --卸载环境变量 ORACLE_HOME=... --安装路径;直接用一句语句也可以,如下 export ORACLE_HOME=/oracledata/.../bin: ...

    Spring 2.0 开发参考手册

    3.3.3. bean属性及构造器参数详解 3.3.4. 使用depends-on 3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    3.3.3. bean属性及构造器参数详解 3.3.3.1. 直接量(基本类型、Strings类型等。) 3.3.3.2. 引用其它的bean(协作者) 3.3.3.3. 内部bean 3.3.3.4. 集合 3.3.3.5. Nulls 3.3.3.6. XML-based configuration metadata ...

    spring chm文档

    3.3.3. bean属性及构造器参数详解 3.3.4. 使用depends-on 3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. ...

    Maven权威指南 很精典的学习教程,比ANT更好用

    坐标详解 9.5.2. 多模块项目 9.5.3. 项目继承 9.6. POM最佳实践 9.6.1. 依赖归类 9.6.2. 多模块 vs. 继承 9.6.2.1. 简单项目 9.6.2.2. 多模块企业级项目 9.6.2.3. 原型父项目 10. 构建生命周期 10.1...

Global site tag (gtag.js) - Google Analytics