绑定变量概述
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
相关推荐
oracle 执行计划详解 Oracle 执行计划是数据库性能调整的关键部分,对于想要学习 Oracle 数据库的朋友非常有帮助。下面是Oracle 执行计划的背景知识和重要概念。 共享 SQL 语句 Oracle 将 SQL 语句及解析后得到的...
"Oracle 执行计划详解" Oracle 执行计划是数据库性能优化的关键。为了更好地理解和优化 Oracle 数据库的执行计划,我们需要了解执行计划的生成过程、优化方法和执行计划的解读方法。 执行计划生成过程 执行计划的...
### Oracle BIEE 变量总结与应用 #### 一、引言 Oracle Business Intelligence Enterprise Edition (BIEE) 是一款强大的商业智能工具,能够帮助组织机构从数据中提取价值并做出更好的决策。在 BIEE 的开发过程中,...
本文档详细解释了 ORACLE 的执行计划背景知识,包括共享 SQL 语句、执行计划的存储和共享、绑定变量的使用、执行计划的生成和共享、执行计划的优化等方面的内容。 一、共享 SQL 语句 ORACLE 对相同的 SQL 语句进行...
- SQL书写规则,比如绑定变量的使用,以及避免在where条件中使用变量判断等。 2. CBO优化案例分析 - 分析了不同的案例背景和系统配置,以及测试方法。 - 提供了SQL调优的思路和方法,包括面对数据分布不均匀、...
- 使用相同的绑定变量名称:即使绑定变量的实际值不同,也必须使用相同的变量名。 - **实例说明**: - 如果两个用户分别使用私有同义词`sal_limit`来访问不同的对象,那么他们的SQL语句不会被共享。 - 如果两个...
- **绑定变量的影响**:如果两个SQL语句中使用了不同的绑定变量名称,即使在运行时这些变量的实际值相同,Oracle也不会认为这两个语句是相同的,因此不会共享执行计划。 #### 总结 通过合理选择优化器模式、利用...
### Oracle语句优化详解 #### 一、Oracle优化器模式的理解与选择 Oracle数据库通过不同的优化器模式来决定执行计划的选择。这些模式包括基于规则的优化(RULE)、基于成本的优化(CBO)以及自动选择(CHOOSE)。 ...
### Oracle语句优化规则详解 #### 一、选用适合的Oracle优化器 Oracle数据库提供了三种主要的优化器:基于规则的优化器(RULE)、基于成本的优化器(COST)和选择性优化器(CHOOSE)。优化器的选择直接影响到SQL...
例如,插入数据时,可以使用变量绑定的方式执行INSERT语句: ```python sql = "INSERT INTO table_name (column1, column2) VALUES (:1, :2)" params = ('value1', 'value2') cursor.execute(sql, params) ``` 这段...
对于绑定变量,必须使用相同名称的绑定变量才能确保SQL语句的共享,即使在运行时,这些变量被赋予了相同的值。 文档中也提到了绑定变量的重要性。绑定变量是在SQL语句中使用占位符代替直接在查询中指定的值,这样...
当多个查询具有相同的结构但不同参数时,使用绑定变量可以使Oracle重用解析计划。例如,动态SQL和存储过程中的参数化查询应尽可能使用绑定变量。 5. **缓存与高速缓冲**: Oracle使用缓存来加速数据访问。共享池中...
例如,合理使用索引、避免全表扫描、使用绑定变量等。其次是SQL语句的结构调整,例如通过重写SQL语句来减少中间结果集的生成,降低资源消耗。 再者,要熟悉Oracle的执行计划分析。执行计划是SQL语句性能的蓝图,...
3. **绑定变量一致**:SQL语句中使用的绑定变量名称也必须完全相同才能共享。 通过以上方法,不仅可以提高Oracle数据库的查询性能,还能有效利用系统资源,降低维护成本。对于大型数据库应用而言,合理设置优化器...
【VC++开发Oracle数据库应用程序详解】 在开发Oracle数据库应用程序时,Visual C++(简称VC)是一种常见的客户端开发工具,尤其适合构建与Oracle数据库交互的应用。本文主要探讨两种使用VC++开发Oracle应用程序的...
优化处理器管理是提升数据库性能的关键,包括合理设置并行度、使用绑定变量等策略。 3. **存储器管理**:Oracle数据库采用了一种称为SGA(系统全局区)的内存结构,其中包含了缓存数据、解析缓冲区、重做日志缓冲区...
4. **绑定变量**:使用绑定变量可以避免硬解析,提高SQL语句的重用率,从而减少解析开销和内存占用。 5. **并行查询**:Oracle支持并行查询,将大任务分解为多个子任务并发执行,以加速处理速度。但过度的并行可能...
Oracle 12c-优化 Hint详解.pdf Oracle 12c-优化 Oracle 索引技术.pdf Oracle 12c 执行计划.pdf ...Oracle 12c 使用绑定变量 VS 不使用绑定变量.pdf Oracle 12c 自动工作负载信息库AWR.pdf Oracle 12c 常用SQL.pdf