天天看點

ORACLE 綁定變量用法總結

之前對ORACLE中的變量一直沒個太清楚的認識,比如說使用:、&、&&、DEIFINE、VARIABLE……等等。今天正好閑下來,上網搜了搜相關的文章,彙總了一下,貼在這裡,友善學習。

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

 在oracle 中,對于一個送出的sql語句,存在兩種可選的解析過程, 一種叫做硬解析,一種叫做軟解析.

一個硬解析需要經解析,制定執行路徑,優化通路計劃等許多的步驟.硬解釋不僅僅耗費大量的cpu,更重要的是會占據重要的們闩(latch)資源,嚴重的影響系統的規模的擴大(即限制了系統的并發行),而且引起的問題不能通過增加記憶體條和cpu的數量來解決。之是以這樣是因為門闩是為了順序通路以及修改一些記憶體區域而設定的,這些記憶體區域是不能被同時修改。當一個sql語句送出後,oracle會首先檢查一下共享緩沖池(shared pool)裡有沒有與之完全相同的語句,如果有的話隻須執行軟分析即可,否則就得進行硬分析。

 而唯一使得oracle 能夠重複利用執行計劃的方法就是采用綁定變量。綁定變量的實質就是用于替代sql語句中的常量的替代變量。綁定變量能夠使得每次送出的sql語句都完全一樣。

1.

sqlplus中如何使用綁定變量,可以通過variable來定義

[c-sharp] view plaincopy

SQL> select * from tt where id=1;  

ID NAME  

---------- ----------------------------------------  

1 test  

SQL> select * from tt where id=2;  

2 test  

SQL> variable i number;  

SQL> exec :i :=1;  

PL/SQL 過程已成功完成。  

SQL> select *from tt where id=:i;  

SQL> exec :i :=2;  

SQL> print i;  

I  

----------  

2  

SQL> select sql_text,parse_calls from v$sql where sql_text like 'select * from t  

t 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的sqlselect *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;  

---------- ----------  

1 a  

2 a  

3 "abc"  

SQL> define a  

SP2-0135: 符号 a 未定義  

SQL> define a=1  

With the Partitioning, OLAP, Data Mining and Real Application Testing options" (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  

SQL> select * from tt where id=&&a;  

原值 1: select * from tt where id=&&a  

SQL> define b='a';  

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'  

SQL> select * from tt where name='&b';  

原值 1: select * from tt where name='&b'  

--執行sql時進行了替換  

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

=%';  

SQL_TEXT  

--------------------------------------------------------------------------------  

select * from tt where name=1  

select * from tt where name='a'  

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 /  

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')  

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> 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)  

5 and b.name like '%parse%'  

6 /  

159 330 345 parse count (total)  

159 331 167 parse count (hard)  

這裡發現hard parse隻增加了2,如果沒有使用綁定變量的話,相信hard parse會更多

4.

過程中的參數會自動轉化為綁定變量

SQL> edit  

已寫入 file afiedt.buf  

1 create or replace procedure proc_test(p_id int, p_name varchar2)  

2 is  

3 begin  

4 insert into tt values(p_id , p_name);  

5 commit;  

6* end;  

SQL> /  

過程已建立。  

SQL> exec proc_test(200,'test');  

--trace file:  

alter session set sql_trace=true  

EXEC #3:c=0,e=749,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=7393908487  

PARSING IN CURSOR #1 len=35 dep=0 uid=31 oct=47 lid=31 tim=7403000735 hv=526484776   

ad='6687b0b8'  

BEGIN proc_test(200,'test'); END;  

PARSE #1:c=0,e=2584,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=7403000727  

PARSING IN CURSOR #6 len=33 dep=1 uid=31 oct=2 lid=31 tim=7403001293 hv=2874748229   

ad='668e9cd8'  

INSERT INTO TT VALUES(:B2 , :B1 )  

PARSE #6:c=0,e=246,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,tim=7403001286  

另外也可以直覺的觀察:

SQL> select sql_text from v$sql where sql_text like '%proc_test%';  

在sqlplus裡執行過程不能觀察出來

下面在plsql developer執行一次過程之後再來看執行的情況

begin -- Call the procedure proc_test(p_id =>:p_id, p_name =>:p_name); end;  

很顯然oracle在執行過程時把參數轉化為綁定變量了,其實從plsql developer中執行過程時的文法就能

看出來:

-- Call the procedure  

proc_test(p_id => :p_id,  

p_name => :p_name);  

在輸入參數清單框上面的執行文法就是這樣的。

5.

在動态sql中使用綁定變量,動态sql中使用綁定變量非常明顯也容易了解,下面給出2個簡單的例子

SQL> set serveroutput on  

   2   v_string varchar2(100);  

   3   v_id tt.id%type ;  

   4   v_name tt.name%type ;  

   5   begin  

   6   v_string:='select * from tt where id=:v_id';  

   7   execute immediate v_string into v_id , v_name using &a;  

   8   dbms_output.put_line(v_id||' '||v_name) ;  

   9   end;  

10   /  

輸入 a 的值:   1  

原值 7: execute immediate v_string into v_id , v_name using &a;  

新值 7: execute immediate v_string into v_id , v_name using 1;  

   3   v_id tt.id%type;  

   6   v_string:='insert into tt values(:id,:name)';  

   7   execute immediate v_string using &id,&name ;  

   8   end;  

   9   /  

輸入 id 的值:   1000  

輸入 name 的值:   'test'  

原值 7: execute immediate v_string using &id,&name ;  

新值 7: execute immediate v_string using 1000,'test' ;  

SQL> select * from tt where id=1000;  

       ID NAME  

   1000 test  

=============================下面加上一些其他變量的使用方法========================= 

eg001(&替換變量)

SQL> select xh,xm from system.xs where zym='&zym';  

輸入 zym 的值:  計算機  

原值    1: select xh,xm from system.xs where zym='&zym'  

新值    1: select xh,xm from system.xs where zym='計算機'  

XH     XM  

------ --------  

061101 王林  

061102 程明  

061103 王燕  

061104 韋嚴平  

061106 李方方  

061107 李明  

061108 林一帆  

061109 張強民  

061110 張蔚  

061111 趙琳  

061113 嚴紅  

已選擇11行。  

  1  select xh 學号,xm 姓名,avg(cj) as 平均成績  

  2* from system.xs_xkb group by xh,xm  

學号   姓名       平均成績  

------ -------- ----------  

061103 王燕             71  

061210 李紅慶           76  

061110 張蔚     91.3333333  

061220 吳薇華           82  

061104 韋嚴平   79.6666667  

061101 王林             78  

061204 馬林林           91  

061106 李方方           72  

061218 孫研             70  

061102 程明             78  

061241 羅林琳           90  

061111 趙琳           80.5  

061109 張強民         76.5  

061216 孫祥欣           81  

061221 劉燕敏           79  

已選擇15行。  

SQL> select * from system.xs_xkb where cj>=&cj;  

輸入 cj 的值:  90  

原值    1: select * from system.xs_xkb where cj>=&cj  

新值    1: select * from system.xs_xkb where cj>=90  

SQL> select xs.xh,&name,kcm,&column  

  2  from system.xs,&kc,system.xs_kc  

  3  where xs.xh=xs_kc.xh and &condition  

  4  and kcm=&kcm  

  5  order by & column;  

輸入 name 的值:  xm  

輸入 column 的值:  cj  

原值    1: select xs.xh,&name,kcm,&column  

新值    1: select xs.xh,xm,kcm,cj  

輸入 kc 的值:  system.kc  

原值    2: from system.xs,&kc,system.xs_kc  

新值    2: from system.xs,system.kc,system.xs_kc  

輸入 condition 的值:  kc.kch=xs_kc.kch  

原值    3: where xs.xh=xs_kc.xh and &condition  

新值    3: where xs.xh=xs_kc.xh and kc.kch=xs_kc.kch  

輸入 kcm 的值:  '離散數學'  

原值    4: and kcm=&kcm  

新值    4: and kcm='離散數學'  

原值    5: order by & column  

新值    5: order by cj  

XH     XM       KCM                      CJ  

------ -------- ---------------- ----------  

061104 韋嚴平   離散數學                 65  

061109 張強民   離散數學                 70  

061101 王林     離散數學                 76  

061102 程明     離散數學                 78  

061106 李方方   離散數學                 80  

061103 王燕     離散數學                 81  

061110 張蔚     離散數學                 89  

eg002(&&替換變量)

--&&替換變量系統一直用同一個值處理,清除用undefine 變量名清除  

  1  select xs.xh,&name,kcm,&&column    

  5* order by &column  

原值    1: select xs.xh,&name,kcm,&&column  

原值    5: order by &column              

已選擇7行。  

eg003

DEFINE[variable[=value]]

UNDEFINE清除定義的變量

SQL> define specialty=通信工程  

SQL> define specialty  

DEFINE SPECIALTY       = "通信工程" (CHAR)  

SQL> select xh,xm,xb,cssj,zxf from system.xs  

  2  where zym='&specialty';  

XH     XM       XB CSSJ                  ZXF  

------ -------- -- -------------- ----------  

061202 王林     男 29-10月-85             40  

061210 李紅慶   女 01-5月 -85             44  

061201 王敏     男 10-6月 -84             42  

061203 王玉民   男 26-3月 -86             42  

061204 馬林林   女 10-2月 -84             42  

061206 李計     女 20-9月 -85             42  

061216 孫祥欣   女 09-3月 -84             42  

061218 孫研     男 09-10月-86             42  

061220 吳薇華   女 18-3月 -86             42  

061221 劉燕敏   女 12-11月-85             42  

061241 羅林琳   女 30-1月 -86             50  

eg004

ACCEPT variable[datatype[NUMBER|CHAR|DATE]][FORMAT format][PROMPT text][HIDE]

SQL> accept num prompt'請輸入課程号:'  

請輸入課程号:101  

SQL> set verify on  

SQL>   

  1  select xh,kcm,cj from system.xs_kc,system.kc  

  2  where xs_kc.kch=kc.kch and kc.kch='&num'  

  3* order by cj  

原值    2: where xs_kc.kch=kc.kch and kc.kch='&num'  

新值    2: where xs_kc.kch=kc.kch and kc.kch='101'  

XH     KCM                      CJ  

------ ---------------- ----------  

061103 計算機基礎               62  

061106 計算機基礎               65  

061218 計算機基礎               70  

061210 計算機基礎               76  

061221 計算機基礎               79  

061101 計算機基礎               80  

061216 計算機基礎               81  

061220 計算機基礎               82  

061241 計算機基礎               90  

061104 計算機基礎               90  

061111 計算機基礎               91  

061204 計算機基礎               91  

061110 計算機基礎               95  

已選擇13行。  

繼續閱讀