`
LJ你是唯一LT
  • 浏览: 244063 次
社区版块
存档分类
最新评论

oracle绑定变量学习

阅读更多
绑定变量(binding variable)

一、为什么要绑定变量

    在oracle 中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析,一种叫做软解析.
一个硬解析需要经解析,制定执行路径,优化访问计划等许多的步骤.硬解释不仅仅耗费大量的cpu,更重要的是会占据重要的门闩(latch)资源,
严重的影响系统的规模的扩大(即限制了系统的并发行), 而且引起的问题不能通过增加内存条和cpu的数量来解决。

   当一个sql语句提交后,oracle会首先检查一下共享缓冲池(shared pool)里有没有与之完全相同的语句,
如果有的话只须执行软分析即可,否则就得进行硬分析。而唯一使得oracle 能够重复利用执行计划的方法就是采用绑定变量。
绑定变量能够使得每次提交的sql语句都完全一样。

   在Oracle中存在两种类型的SQL语句,一类为DDL语句,他们是从来不会共享使用的,也就是每次执行都需要进行硬解析。
还有一类就是DML语句,他们会根据情况选择要么进行硬解析,要么进行软解析。


二、在Oracle中SQL语句的解析步骤如下:
1、 语法检测。判断一条SQL语句的语法是否符合SQL的规范,比如执行:SQL> selet * from emp; 我们就可以看出由于Select关键字少了一个“c”,这条语句就无法通过语法检验的步骤了。
2、 语义检查。语法正确的SQL语句在解析的第二个步骤就是判断该SQL语句所访问的表及列是否准确,用户是否有权限访问或更改相应的表或列。
3、 检查共享池中是否有相同的语句存在。假如执行的SQL语句已经在共享池中存在同样的副本,那么该SQL语句将会被软解析,也就是可以重用已解析过的语句的 执行计划和优化方案,可以忽略语句解析过程中最耗费资源的步骤。这个步骤又可以分为两个步骤:
(1)验证SQL语句是否完全一致。
     Oracle将会对传递进来的SQL语句使用HASH函数运算得出HASH值,再与共享池中现有语句的 HASH值进行比较看是否一一对应。
     现有数据库中SQL语句的HASH值我们可以通过访问v$sql、v$sqlarea、v$sqltext等数据字典中的HASH_VALUE列查询得出。

(2)验证SQL语句执行环境是否相同。比如同样一条SQL语句,一个查询会话加了/*+ first_rows */的HINT,
另外一个用户加/*+ all_rows */的HINT,他们就会产生不同的执行计划,尽管他们是查询同样的数据。

4、 Oracle根据提交的SQL语句再查询相应的数据对象是否有统计信息。
    如果有统计信息的话,那么CBO将会使用这些统计信息产生所有可能的执行计划(可能多达成千上万个)和相应的Cost,
最终选择Cost最低的那个执行计划。如果查询的数据对象无统计信息,则按RBO的默认规则选择相应的执行计划。
这个步骤也是解析中最耗费资源的,因此我们应该极力避免硬解析的产生。至此,解析的步骤已经全部完成,
Oracle将会根据解析产生的执行计划执行SQL语句和提取相应的数据。


三、绑定变量示例
普通sql语句:
SQL> select * from mytest where random_id=30;
SQL> select * from mytest where random_id=31;
SQL> select * from mytest where random_id=32;

含绑定变量的sql 语句:
SQL> select * from mytest where random_id=:x;
SQL> select * from mytest where random_id='&random_id';

Sql*plus 中使用绑定变量:
SQL> set timing on
SQL> variable y number;
SQL> exec :y :=39;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
SQL> select * from mytest where random_id=:y;
SQL> exec :y :=21;
PL/SQL procedure successfully completed.
SQL> select * from mytest where random_id=:y;   ---改变y的值,重复执行此sql

pl/sql中使用绑定变量:
pl/sql很多时候都会自动绑定变量,如下例:
SQL> create or replace procedure p_mytest(p_no in number)
as
  begin
    update mytest set random_id=random_id+2 where random_id = p_no;
    commit;
  end;
/
Procedure created.
Elapsed: 00:00:00.17

SQL> exec p_mytest(20);   ---执行该存储过程
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.02

在pl/sql中,引用变量即是引用绑定变量.
但在pl/sql中动态sql并不是这样,在vb,java以及其他应用程序中都得显式地利用绑定变量。

SQL> select sql_id,hash_value,plan_hash_value,executions,sql_text from v$sql where upper(sql_text) like 'SELECT * FROM MYTEST%';

SQL_ID        HASH_VALUE PLAN_HASH_VALUE      EXECUTIONS SQL_TEXT
------------- ---------- --------------- ---------- --------------------------------------------------------------------------------
fvbfv6r7xhrx0 3487063968      1137542690          5 select * from mytest where ROWNUM <10
cw7d99wy2d7sa 1009164042      1137542690          3 select * from mytest where ROWNUM <5
6dwn6j9cw1dp2 1505801890      1692938441          2 select * from mytest where random_id=:x    ---包含一次软解析
g7mfz99r6dfpw 1852226236      1692938441          1 select * from mytest where random_id='39'
8v2bw6pq8tx7m 1821177075      1692938441          0 select * from mytest where random_id=30
0zyay1mv7kvys 4135153624      1137542690          2 select * from mytest where rownum<5
bdbtr8cb7fzka  376929866      1692938441          1 select * from mytest where random_id=20

说明:每条语句都有一个唯一的HASH_VALUE,相当于你语句的一个ID,
v$sql和v$sql_plan的hash_value,如果两条相同的话ORACLE会认为这两条语句是同一条语句,不会再次做硬解析,plan_hash_value是执行计划的hash值,数值的大小没啥意义。

查看某个sql具体的执行计划:
SQL> select plan_table_output from table(dbms_xplan.display_awr('g7mfz99r6dfpw'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID g7mfz99r6dfpw
--------------------
select * from mytest where random_id='39'
Plan hash value: 1692938441
----------------------------------------------------------------------------
| Id  | Operation         | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |       |       |    24 (100)|          |
|   1 |  TABLE ACCESS FULL| MYTEST |   107 |   213K|    24   (0)| 00:00:01 |
----------------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement (level=2)
17 rows selected


1.对比区别
1.1 未绑定变量
set echo on;
set serveroutput on; (把执行结果显示出来)
set timing on(打开记时器.)

SQL> declare
  type rc is ref cursor;
  l_rc rc;
  l_du all_objects.OBJECT_NAME%type;
  l_ti number default dbms_utility.get_time;   --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_du;
  close l_rc;
  end loop;
  dbms_output.put_line(round((dbms_utility.get_time-l_ti)/100,2) ||'seconds');  --通过差集/100 可以大概预估整个过程执行时间
end;
/
64.2seconds
PL/SQL procedure successfully completed.
Elapsed: 00:01:04.31                      ---用时64s

1.2 绑定变量
SQL> declare
  type rc is ref cursor;
  l_rc rc;
  l_du all_objects.OBJECT_NAME%type;
  l_ti 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_du;
  close l_rc;
  end loop;
  dbms_output.put_line(round((dbms_utility.get_time-l_ti)/100,2) ||'seconds');
end;
/
.52seconds

PL/SQL procedure successfully completed.
Elapsed: 00:00:00.55                    ---用时不超过1s


2)绑定方法
2.1 静态绑定变量
set serveroutput on;
set timing on;
declare
  l_num number;
  l_p1  int;
begin
  l_p1:=5;
  select count(*) into l_num from mytest where random_id = l_p1;
  dbms_output.put_line(l_num);
end;
/
94
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
在上面的情况,Oracle会自己绑定变量,select语句只会编译一次。

2.2 动态绑定变量
declare
  l_sql varchar2(2000);
  l_num number;
  l_p1  int;
begin
  l_p1:=5;
  l_sql:='select count(*) into :z from mytest where random_id =:y';
  execute immediate l_sql into l_num using l_p1;
  dbms_output.put_line(l_num);
end;
/
94
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00

2.3 dbms_output的绑定变量使用
declare
  l_id  integer;
  l_ti  number default dbms_utility.get_time;
  l_num integer;
begin
  l_id := dbms_sql.open_cursor;
  for i in 1 .. 1000 loop
    dbms_sql.parse(l_id,'insert into t3 values(:username,:user_id,sysdate)',dbms_sql.v7);
    dbms_sql.bind_variable(l_id, 'username', 'test' || to_char(i));
    dbms_sql.bind_variable(l_id, 'user_id', i);
    l_num := dbms_sql.execute(l_id);
  end loop;
  dbms_sql.close_cursor(l_id);
  dbms_output.put_line(round((dbms_utility.get_time - l_ti) / 100, 2) ||'seconds');
end;
/
.4seconds
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.41                        ---用时0.4s

查看数据:
SQL> select count(*) from t3;
  COUNT(*)
----------
      1000

SQL> select * from t3 where rownum <5;
USERNAME   USER_ID RECORD_TIME
------------------------------ ---------- ------------------------------
test879       879 25-DEC-15 03.46.31.000000 PM
test880       880 25-DEC-15 03.46.31.000000 PM
test881       881 25-DEC-15 03.46.31.000000 PM
test882       882 25-DEC-15 03.46.31.000000 PM

说明:
     dbms_sql.parse(v_cursor, v_sql, dbms_sql.native); --解析动态SQL语句;
     dbms_sql.bind_variable(v_cursor, ':sid', s_id);   --绑定输入参数;

四、查询占用资源较多的sql
select sql_text ,sharable_mem from v$sql where sharable_mem > '100000' order by sharable_mem ;   --占用内存超过100k的sql内容

五. 绑定变量使用限制条件是什么?
    为了不重复解析相同的SQL语句,在第一次解析之后, ORACLE将SQL语句存放在内存中.这块位于系统全局区域SGA的共享池(shared buffer pool)中
的内存可以被所有的数据库用户共享. 因此,当你执行一个SQL语句(有时被称为一个游标)时,如果它和之前的执行过的语句完全相同,
ORACLE就能很快获得已经被解析的语句以及最好的执行路径. ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用.

   数据库管理员必须在init.ora中为这个区域设置合适的参数,当这个内存区域越大,就可以保留更多的语句,当然被共享的可能性也就越大了.
当你向ORACLE 提交一个SQL语句,ORACLE会首先在这块内存中查找相同的语句.这里需要注明的是,ORACLE对两者采取的是一种严格匹配,
要达成共享,SQL语句必须完全相同(包括空格,换行等).
共享的语句必须满足三个条件:

A. 字符级的比较:
当前被执行的语句和共享池中的语句必须完全相同.
例如:
SELECT * FROM EMP;
和下列每一个都不同
SELECT * from EMP;
Select * From Emp;
SELECT * FROM EMP;

B. 两个语句所指的对象必须完全相同:
例如:tina.mytest

C. 两个SQL语句中必须使用相同的名字的绑定变量(bind variables)
下面两个语句是不同的(即使在运行时,赋于不同的绑定变量相同的值)
select * from mytest where random_id=:x;
select * from mytest where random_id=:y;


补充:在Java中的使用绑定变量
Java代码
PreparedStatement pstmt = conn.prepareStatement("select * from table_name where id = ?" );;  
pstmt.setInt(1 ,1 );;  
rset = pstmt.executeQuery();;  
...  
pstmt.setInt(1 ,2 );;  
rset = pstmt.executeQuery();;  

这样Oracle数据库就知道你实际上用的都是同一条sql语句,会以这样的形式:
select * from table_name where id = :1

解析执行后存放在sql区域里面,当以后再有一样的sql的时候,把参数替换一下,就立刻执行,不需要再解析sql了。
既加快了sql执行速度,也不会占有过多SGA的share pool。

String v_id = 'xxxxx';
String v_sql = 'select name from ta where id = ? '; //嵌入绑定变量
stmt = con.prepareStatement( v_sql );
stmt.setString(1, v_id ); //为绑定变量赋值
stmt.executeQuery();
在Java中,结合使用setXXX 系列方法,可以为不同数据类型的绑定变量进行赋值,从而大大优化了SQL 语句的性能。

分享到:
评论

相关推荐

    oracle 数据库的绑定变量特性及应用

    Oracle 数据库的绑定变量特性及应用 绑定变量是 Oracle 数据库的一种特性,它旨在提高数据库系统的性能和可扩展性。在本文中,我们将详细地探讨绑定变量的目的、命名方法、使用限制条件和应用实例。 为什么使用...

    在Java中实现Oracle变量的绑定方法 .doc

    为了解决这些问题,我们可以使用预编译的PreparedStatement对象来绑定变量,例如: ```java String sql = "select name from oms_user where id=?"; PreparedStatement pstmt = connection.prepareStatement(sql); ...

    浅谈oracle 数据库的绑定变量特性及应用

    Oracle数据库的绑定变量特性及其应用是数据库管理中的一个重要概念,特别是在处理大量数据和优化SQL查询性能时。绑定变量,也称为参数化查询或占位符,是SQL语句中用特殊符号(如“:var”)代替具体值的方式,使得同...

    Java中Oracle操作绑定变量使用用户工具模块解决方案

    ### Java中Oracle操作绑定变量使用用户工具模块解决方案 #### 一、背景介绍 在Java开发过程中,特别是与Oracle数据库交互的应用场景中,SQL语句的编写及执行效率一直是开发者关注的重点之一。为了提高SQL语句的...

    Oracle绑定变量窥视功能深度分析.pdf

    Oracle 绑定变量窥视功能深度分析 Oracle 绑定变量窥视功能是 Oracle 数据库中的一种功能,可以使 SQL 语句共享执行计划,从而提高数据库性能。该功能通过在绑定变量中存储执行计划,从而避免了每次执行 SQL 语句...

    也谈oracle 数据库的绑定变量特性及应用

    Oracle 数据库的绑定变量特性是其优化性能的关键技术之一,主要应用于提高数据库应用程序的可伸缩性和效率。绑定变量允许开发者创建动态SQL语句,其中的变量在执行时才提供具体的值,而不是硬编码到查询中。这种做法...

    Oracle数据库绑定变量特性及应用

    Oracle数据库的绑定变量特性是其优化SQL性能的关键技术之一,对于构建高效、可扩展和稳定的数据库系统至关重要。本文将深入探讨绑定变量的原理、优势以及如何在实际应用中使用。 首先,为什么我们要使用绑定变量?...

    oracle 的绑定变量

    【Oracle的绑定变量】在数据库管理系统中,尤其是Oracle OLTP(在线事务处理)系统中,绑定变量是一个关键的性能优化技术。它对于提高系统效率、减少资源消耗具有显著作用。绑定变量的基本思想是通过变量来替代SQL...

    Oracle 中的变量绑定

    相反,如果使用绑定变量,Oracle会尝试在共享池(Shared Pool)中查找相同的基本SQL结构,如果找到,就进行软分析(Soft Parse),从而避免重复的工作。 不使用绑定变量的另一个负面影响是共享池中的SQL语句数量...

    Oracle数据库的绑定变量特性及应用.pdf

    Oracle数据库的绑定变量是一种优化策略,它在提升数据库性能、可扩展性和稳定性方面扮演着重要角色。绑定变量的使用能够显著改善SQL语句的执行效率,尤其是在处理大量重复查询时。本文将深入探讨绑定变量的原理、...

    如何绑定变量

    ### 如何绑定变量 在OLTP(Online Transaction Processing...通过以上方法,我们可以有效地在Oracle数据库中使用绑定变量来优化SQL语句的执行效率,特别是在OLTP系统中,这种方法对于提升系统的整体性能具有重要意义。

    查找未使用绑定变量sql.sql

    查找未使用绑定变量sql.sql

    sql绑定变量

    标题与描述中的“SQL绑定变量”这一知识点,主要聚焦于SQL语句中如何使用变量,尤其是在存储过程或函数中动态构建SQL语句时的关键技术。绑定变量允许在SQL语句中使用程序变量作为参数,这不仅提高了代码的可读性和...

    PLSQL绑定变量用法小结归纳.pdf

    由于我们使用了绑定变量,所以Oracle只需要软分析一次,而不需要每次都进行硬分析,从而提高了数据库的性能。 需要注意的是,绑定变量可以在PL/SQL过程中使用,例如: Declare i number; Begin i := 1; Select ...

    Oracle_数据库的绑定变量特性及应用终稿.pdf

    Oracle数据库的绑定变量是提升系统性能和可扩展性的重要特性,尤其对于大型企业级应用而言,正确使用绑定变量能够显著优化数据库操作。绑定变量的主要作用是减少解析和优化过程,提高查询效率,节省系统资源。 首先...

    在PHP中利用绑定变量提高Oracle的存储效率.pdf

    在处理大量动态查询时,使用绑定变量可以显著减少Oracle的解析次数,减轻SGA的压力,进而提升系统的整体性能。 绑定变量的工作原理是:在PHP代码中,我们不直接将变量值插入到SQL语句中,而是声明一个占位符(如`:...

    oracle biee变量总结

    ### Oracle BIEE 变量总结与应用 #### 一、引言 Oracle Business Intelligence Enterprise Edition (BIEE) 是一款强大的商业智能工具,能够帮助组织机构从数据中提取价值并做出更好的决策。在 BIEE 的开发过程中,...

    oracle变量绑定[文].pdf

    绑定变量的使用遵循了Oracle Shared Pool的设计理念,提高了SQL语句的复用性和系统整体性能。因此,在开发Java应用程序并与Oracle数据库交互时,应尽可能使用绑定变量,以优化数据库操作,提升系统效率。

    动态SQL与绑定变量

    动态SQL与绑定变量是数据库编程中的重要概念,尤其在Oracle数据库中被广泛应用。动态SQL允许在运行时构建和执行SQL语句,而绑定变量则是在动态SQL中用于替代具体值的占位符,使得SQL语句更为灵活和高效。 ### 1. ...

Global site tag (gtag.js) - Google Analytics