ORACLE 绑定变量用法总结

之前对ORACLE中的变量一直没个太清楚的认识,比如说使用:&、&&、DEFINE、VARIABLE……等等。今天正好闲下来,上网搜了搜相关的文章,汇总了一下,贴在这里,方便学习。

==================================================================================

在oracle 中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析,一种叫做软解析.

一个硬解析需要经解析,制定执行路径,优化访问计划等许多的步骤.硬解析不仅仅耗费大量的cpu,更重要的是会占据重要的门闩(latch)资源,严重的影响系统的规模的扩大(即限制了系统的并发行),而且引起的问题不能通过增加内存条和cpu的数量来解决。之所以这样是因为门闩是为了顺序访问以及修改一些内存区域而设置的,这些内存区域是不能被同时修改。当一个sql语句提交后,oracle会首先检查一下共享缓冲池(shared pool)里有没有与之完全相同的语句,如果有的话只须执行软分析即可,否则就得进行硬分析。

而唯一使得oracle 能够重复利用执行计划的方法就是采用绑定变量。绑定变量的实质就是用于替代sql语句中的常量的替代变量。绑定变量能够使得每次提交的sql语句都完全一样。


1.

sqlplus中如何使用绑定变量?可以通过variable来定义
SQL> select * from tt where id=1;  
 
ID NAME  
---------- ----------------------------------------  
1 test  
 
SQL> select * from tt where id=2;  
 
ID NAME  
---------- ----------------------------------------  
2 test  
 
SQL> variable i number;  
SQL> exec :i :=1;  
 
PL/SQL 过程已成功完成。  
 
SQL> select *from tt where id=:i;  
 
ID NAME  
---------- ----------------------------------------  
1 test  
 
SQL> exec :i :=2;  
 
PL/SQL 过程已成功完成。  
 
SQL> select *from tt where id=:i;  
 
ID NAME  
---------- ----------------------------------------  
2 test  
 
SQL> print i;  
 
I  
----------  
2  
 
SQL> select sql_text,parse_calls from v$sql where sql_text like 'select * from tt where id=%';  
 
SQL_TEXT PARSE_CALLS  
------------------------------------------------------------ -----------  
select * from tt where id=2 1  
select * from tt where id=1 1  
select * from tt where id=:i 2  
SQL>

从上面试验发现绑定变量i的使用使查询id=1和id=2的sql select * from tt where id=:i得以重复使用,从而避免了hard parse,这里的PARSE_CALLS=2包括了一次soft parse



2.

前两天看到有人在pub上问在sqlplus中通过define和variable定义的变量的区别。
其实define定义的我理解不是变量而是字符常量,通过define定义之后,在通过&或者&&引用的时候不需要输入了,仅此而已。oracle在执行的时候自动用值进行了替换;
而variable定义的是绑定变量,上面已经提到。

C:>sqlplus xys/manager  
SQL*Plus: Release 11.1.0.6.0 - Production on 星期二 4月 1 14:03:00 2008  
Copyright (c) 1982, 2007, Oracle. All rights reserved.  
 
连接到:  
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production  
With the Partitioning, OLAP, Data Mining and Real Application Testing options  

SQL> define  

DEFINE _DATE = "01-4月 -08" (CHAR)  
DEFINE _CONNECT_IDENTIFIER = "db11" (CHAR)  
DEFINE _USER = "XYS" (CHAR)  
DEFINE _PRIVILEGE = "" (CHAR)  
DEFINE _SQLPLUS_RELEASE = "1101000600" (CHAR)  
DEFINE _EDITOR = "Notepad" (CHAR)  
DEFINE _O_VERSION = "Oracle Database 11g Enterprise Edition Release 11.1.0.  
6.0 - Production  
With the Partitioning, OLAP, Data Mining and Real Application Testing options" (  
CHAR)  
DEFINE _O_RELEASE = "1101000600" (CHAR)  

SQL> select * from tt;  

ID NAME  
---------- ----------  
1 a  
2 a  
3 "abc"
 
SQL> define a  
SP2-0135: 符号 a 未定义
 
SQL> define a=1  

SQL> define  

DEFINE _DATE = "01-4月 -08" (CHAR)  
DEFINE _CONNECT_IDENTIFIER = "db11" (CHAR)  
DEFINE _USER = "XYS" (CHAR)  
DEFINE _PRIVILEGE = "" (CHAR)  
DEFINE _SQLPLUS_RELEASE = "1101000600" (CHAR)  
DEFINE _EDITOR = "Notepad" (CHAR)  
DEFINE _O_VERSION = "Oracle Database 11g Enterprise Edition Release 11.1.0.  
6.0 - Production  
With the Partitioning, OLAP, Data Mining and Real Application Testing options" (CHAR)  
DEFINE _O_RELEASE = "1101000600" (CHAR)  
DEFINE A = "1" (CHAR)  

--通过上面显示define定义的应该是字符(串)常量。  

SQL> select * from tt where id=&a;  
原值 1: select * from tt where id=&a  
新值 1: select * from tt where id=1  

ID NAME  
---------- ----------  
1 a  

SQL> select * from tt where id=&&a;  
原值 1: select * from tt where id=&&a  
新值 1: select * from tt where id=1  

ID NAME  
---------- ----------  
1 a  

SQL> define b='a';  

SQL> define  

DEFINE _DATE = "01-4月 -08" (CHAR)  
DEFINE _CONNECT_IDENTIFIER = "db11" (CHAR)  
DEFINE _USER = "XYS" (CHAR)  
DEFINE _PRIVILEGE = "" (CHAR)  
DEFINE _SQLPLUS_RELEASE = "1101000600" (CHAR)  
DEFINE _EDITOR = "Notepad" (CHAR)  
DEFINE _O_VERSION = "Oracle Database 11g Enterprise Edition Release 11.1.0.  
6.0 - Production  
With the Partitioning, OLAP, Data Mining and Real Application Testing options" (  
CHAR)  
DEFINE _O_RELEASE = "1101000600" (CHAR)  
DEFINE A = "1" (CHAR)  
DEFINE B = "a" (CHAR)  
 
--如果是字符类型那么在引用时别忘了加上单引号,另外通过define定义之后在引用时不需要输入了。  
SQL> select * from tt where name=&&b;  
原值 1: select * from tt where name=&&b  
新值 1: select * from tt where name=a  
select * from tt where name=a  
*  
第 1 行出现错误:  
ORA-00904: "A": 标识符无效  
 
SQL> select * from tt where name='&&b';  
原值 1: select * from tt where name='&&b'  
新值 1: select * from tt where name='a'  

ID NAME  
---------- ----------  
1 a  
2 a  

SQL> select * from tt where name='&b';  
原值 1: select * from tt where name='&b'  
新值 1: select * from tt where name='a'  

ID NAME  
---------- ----------  
1 a  
2 a  

--执行sql时进行了替换  

SQL> select sql_text from v$sql where sql_text like 'select * from tt where name=%';  

SQL_TEXT  
--------------------------------------------------------------------------------  
select * from tt where id=1  
select * from tt where name='a'  
SQL>  


3.

oracle在解析sql时会把plsql中定义的变量转为绑定变量

SQL> create table tt(id int , name varchar2(10));  
表已创建。  
 
SQL> alter session set sql_trace=true;  
会话已更改。  
 
SQL> declare  
2 begin  
3 for i in 1..100 loop  
4 insert into tt values(i,'test');  
5 end loop;  
6 commit;  
7 end;  
8 /  
 
PL/SQL 过程已成功完成。  
 
SQL> alter session set sql_trace=false;  

--trace file:  
=====================  
PARSING IN CURSOR #3 len=90 dep=0 uid=31 oct=47 lid=31 tim=7109565004 hv=962259239   
 
ad='668ec528'  
declare  
begin  
for i in 1..100 loop  
insert into tt values(i,'test');  
end loop;  
commit;  
end;  
END OF STMT  
PARSE #3:c=15625,e=5678,p=0,cr=3,cu=0,mis=1,r=0,dep=0,og=1,tim=7109564996  
=====================  
PARSING IN CURSOR #5 len=34 dep=1 uid=31 oct=2 lid=31 tim=7109565520 hv=1299226876   
 
ad='66869934'  
INSERT INTO TT VALUES(:B1 ,'test')  
END OF STMT  
PARSE #5:c=0,e=226,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,tim=7109565513  
=====================  

另外从hard parse的数据量上其实也可以大致猜测oracle会把plsql中定义的变量转换为绑定变量处理

SQL> connect /as sysdba  
已连接。  
SQL> shutdown immediate  
数据库已经关闭。  
已经卸载数据库。  
ORACLE 例程已经关闭。  
SQL> startup  
ORACLE 例程已经启动。  
 
Total System Global Area 167772160 bytes  
Fixed Size 1247900 bytes  
Variable Size 67110244 bytes  
Database Buffers 96468992 bytes  
Redo Buffers 2945024 bytes  
数据库装载完毕。  
数据库已经打开。
 
SQL> connect xys/manager  
已连接。  

SQL> drop table tt;  
表已删除。  
 
SQL> create table tt(id int , name varchar2(10));  
表已创建。  

SQL> col name format a30  

SQL> select a.*,b.name  
2 from v$sesstat a , v$statname b  
3 where a.statistic#=b.statistic#  
4 and a.sid=(select distinct sid from v$mystat)  
5 and b.name like '%parse%';  
 
SID STATISTIC# VALUE NAME  
---------- ---------- ---------- ------------------------------  
159 328 39 parse time cpu  
159 329 74 parse time elapsed  
159 330 339 parse count (total)  
159 331 165 parse count (hard)  
159 332 0 parse count (failures)  
 
SQL> declare  
2 begin  
3 for i in 1..100 loop  
4 insert into tt values(i,'test');  
5 end loop;  
6 commit;  
7 end;  
8 /  
 
PL/SQL 过程已成功完成。  
 
SQL> select a.*,b.name  
2 from v$sesstat a , v$statname b  
3 where a.statistic#=b.statistic#  
4 and a.sid=(select distinct sid from v$mystat)  
5 and b.name like '%parse%'  
6 /  
 
SID STATISTIC# VALUE NAME  
---------- ---------- ---------- ------------------------------  
159 328 39 parse time cpu  
159 329 74 parse time elapsed  
159 330 345 parse count (total)  
159 331 167 parse count (hard)  
159 332 0 parse count (failures)  
 
SQL>  

这里发现hard parse只增加了2,如果没有使用绑定变量的话,相信hard parse会更多


4.

过程中的参数会自动转化为绑定变量
SQL> edit  

你可能感兴趣的:(oracle基础)