1. 程式人生 > >oracle繫結變數使用方法總結

oracle繫結變數使用方法總結

在Oracle中,對於一個提交的sql語句,存在兩種可選的解析過程,硬解析和軟解析。

一個硬解析需要經解析,制定執行路徑,優化訪問計劃等步驟。硬解析不僅僅會耗費大量的cpu,更重要的是會佔據重要的閂(latch)資源。唯一使得oracle能夠重複利用執行計劃的方法就是採用繫結變數。繫結變數的實質就是使用變數來代替sql語句中的常量。繫結變數能夠使得每次提交的sql語句都完全一樣。

1. sqlplus中使用variable來定義

SQL> select * from t where id=1;

        ID NAME
---------- --------------------------------
         1 test

SQL> select * from t where id=2;

        ID NAME
---------- --------------------------------
         2 test2

SQL> variable i number;
SQL> exec :i :=1;

PL/SQL procedure successfully completed.

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

        ID NAME
---------- --------------------------------
         1 test

SQL> exec :i :=2;

PL/SQL procedure successfully completed.

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

        ID NAME
---------- --------------------------------
         2 test2
SQL> select sql_text,parse_calls from v$sql where sql_text like 'select * from t where id=%';

SQL_TEXT
--------------------------------------------------------------------------------
PARSE_CALLS
-----------
select * from t where id=2
          1

select * from t where id=1
          1

select * from t where id=:i  --可以看到這條sql被呼叫了兩次,這兩次的使用就包括了一次soft parse

2.  (誤區)sqlplus中通過define定義的並不是變數,而只是字元常量,define定義之後,再通過&或&&引用的時候就不需要再輸入了,oracle在執行的時候回自動用定義的值進行替換,僅此而已,並不是繫結變數。

SQL> define a=1
SQL> define
DEFINE _DATE           = "30-OCT-16" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "ORCL" (CHAR)
DEFINE _USER           = "SYS" (CHAR)
DEFINE _PRIVILEGE      = "AS SYSDBA" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1102000400" (CHAR)
DEFINE _EDITOR         = "ed" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options" (CHAR)
DEFINE _O_RELEASE      = "1102000400" (CHAR)
DEFINE A               = "1" (CHAR)
SQL> select * from t where id=&a;
old   1: select * from t where id=&a
new   1: select * from t where id=1

        ID NAME
---------- --------------------------------
         1 test

&&和&一樣的功能,不過&&替代過一次之後就不需要再輸入了,可以多次替代。
SQL> select * from t where id=&b;
Enter value for b: 2
old   1: select * from t where id=&b
new   1: select * from t where id=2

        ID NAME
---------- --------------------------------
         2 test2

SQL> select * from t where id=&b; 
Enter value for b: 2
old   1: select * from t where id=&b
new   1: select * from t where id=2

        ID NAME
---------- --------------------------------
         2 test2

SQL> select * from t where id=&&b;
Enter value for b: 2
old   1: select * from t where id=&&b
new   1: select * from t where id=2

        ID NAME
---------- --------------------------------
         2 test2

SQL> select * from t where id=&&b;
old   1: select * from t where id=&&b
new   1: select * from t where id=2

        ID NAME
---------- --------------------------------
         2 test2

另外,如果define定義的是字元型別,在引用時需要加上單引號
SQL> select * from t where name=&c;
old   1: select * from t where name=&c
new   1: select * from t where name=test
select * from t where name=test
                           *
ERROR at line 1:
ORA-00904: "TEST": invalid identifier


SQL> select * from t where name='&c';
old   1: select * from t where name='&c'
new   1: select * from t where name='test'

        ID NAME
---------- --------------------------------
         1 test
可以看到,在執行sql的時候oracle自動進行了替換
SQL> select sql_text from v$sql where sql_text like 'select * from t where name=%';

SQL_TEXT
--------------------------------------------------------------------------------
select * from t where name='test'

3. oracle在解析sql時會把plsql中定義的變數轉為繫結變數

SQL> create table tt(id int,name varchar2(10));

Table created.

SQL> alter session set sql_trace=true;

Session altered.

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 procedure successfully completed.

SQL> alter session set sql_trace=false;

Session altered.

trace檔案內容:

*** 2016-10-30 12:11:22.815
CLOSE #140170997623912:c=0,e=6,dep=0,type=0,tim=1477800682815427
=====================
PARSING IN CURSOR #140170997623912 len=92 dep=0 uid=0 oct=47 lid=0 tim=1477800682817922 hv=218581220 ad='8c89d9b0' sqlid='6pdgqjs6hfk74'
declare
begin
for i in 1 .. 100 loop
insert into tt values(i,'test');
end loop;
commit;
end;
END OF STMT
PARSE #140170997623912:c=1999,e=2431,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=1477800682817921
=====================
PARSING IN CURSOR #140170996439488 len=34 dep=1 uid=0 oct=2 lid=0 tim=1477800682818383 hv=1299226876 ad='86bc23a8' sqlid='9j06ydd6r187w'
INSERT INTO TT VALUES(:B1 ,'test')
END OF STMT

從硬解析的增長也可以看出:

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%';

SQL> col name format a30
SQL> /

       SID STATISTIC#      VALUE NAME
---------- ---------- ---------- ------------------------------
        29        264          0 ADG parselock X get attempts
        29        265          0 ADG parselock X get successes
        29        622          4 parse time cpu
        29        623          8 parse time elapsed
        29        624        238 parse count (total)
        29        625        155 parse count (hard)
        29        626          0 parse count (failures)
        29        627          0 parse count (describe)

8 rows selected.

執行前的硬解析數為155
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 procedure successfully completed.

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
---------- ---------- ---------- ------------------------------
        29        264          0 ADG parselock X get attempts
        29        265          0 ADG parselock X get successes
        29        622          4 parse time cpu
        29        623          8 parse time elapsed
        29        624        242 parse count (total)
        29        625        157 parse count (hard)
        29        626          0 parse count (failures)
        29        627          0 parse count (describe)

8 rows selected.

執行後的為157,只增長了兩個,如果不是使用了繫結變數,硬解析數絕對不止兩個

4. 儲存過程中的引數會自動轉化為繫結變數

SQL> 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;
  7  /

Procedure created.

SQL> alter session set sql_trace=true;

Session altered.

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

PL/SQL procedure successfully completed.

SQL> alter session set sql_trace=false;

Session altered.

trace檔案內容:

*** 2016-10-31 04:11:23.421
CLOSE #140585231805712:c=0,e=6,dep=0,type=0,tim=1477858283421964
=====================
PARSING IN CURSOR #140585231805712 len=35 dep=0 uid=0 oct=47 lid=0 tim=1477858283423073 hv=526484776 ad='86b57878' sqlid='asc6yd8gq3198'
BEGIN proc_test(200,'test'); END;
END OF STMT
PARSE #140585231805712:c=999,e=1047,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=1477858283423072
=====================
PARSING IN CURSOR #140585233135112 len=32 dep=1 uid=0 oct=2 lid=0 tim=1477858283423304 hv=1422618771 ad='8697d9b8' sqlid='1yqc845acqw4m'
INSERT INTO TT VALUES(:B2 ,:B1 )
END OF STMT
PARSE #140585233135112:c=0,e=100,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,plh=0,tim=1477858283423304
其實從儲存過程的呼叫過程也可以看出是使用了繫結變數
begin
-- Call the procedure
proc_test(p_id => :p_id,
p_name => :p_name);
end;

5. 動態sql中使用繫結變數

a. 直接使用遊標中的值拼接

[[email protected] scripts]$ cat sql_parse1.sql
declare
cursor test_cur is select id,name from tt;
begin
for i in test_cur loop
execute immediate 'insert into tt values('||i.id||','||chr(39)||i.name||chr(39)||')';
end loop;
commit;
end;
這樣直接使用遊標中的值拼接是屬於非繫結變數,為硬解析
SQL> alter system flush shared_pool;

System altered.

SQL> @sql_parse1.sql

PL/SQL procedure successfully completed.

SQL> set linesize 200
SQL> col hash_value format 9999999999
SQL> col sql_id format 99
SQL> col child_latch format 99
SQL> col version_count format 99
SQL> col sql_text format a40
SQL> col parse_calls format 999
SQL> select hash_value,sql_id,child_latch,version_count,sql_text,parse_calls from v$sqlarea where sql_text like 'insert into tt%';
 HASH_VALUE SQL_ID        CHILD_LATCH VERSION_COUNT          SQL_TEXT                                           PARSE_CALLS
----------- ------------- ----------- ------------- -------------------------------------------------- -----------
 3161064081 196c4s2y6n0nj           0             1 insert into tt values(45,'test')                             1
 3718124844 6hfpagbftw59c           0             1 insert into tt values(70,'test')                             1
 4046592725 c5txty7sm46qp           0             1 insert into tt values(28,'test')                             1
  961289967 4n0n3dnwns7rg           0             1 insert into tt values(30,'test')                             1
 2124685404 g70mmhxza882w           0             1 insert into tt values(26,'test')                             1
  608576974 3nm07v4k4c9ff           0             1 insert into tt values(31,'test')                             1
 3770952793 2xcry8ghc8b2t           0             1 insert into tt values(1,'test')                              1

b. 繫結變數寫法

[[email protected] scripts]$ cat sql_parse2.sql
declare
cursor test_cur is select id,name from tt;
begin
for i in test_cur loop
execute immediate 'insert into tt values(:a,:b)' using i.id,i.name;
end loop;
commit;
end;
/

SQL> alter system flush shared_pool;

System altered.

SQL> @sql_parse2.sql

PL/SQL procedure successfully completed.

SQL> select hash_value,sql_id,child_latch,version_count,sql_text,parse_calls from v$sqlarea where sql_text like 'insert into tt%';

 HASH_VALUE SQL_ID        CHILD_LATCH VERSION_COUNT SQL_TEXT                                           PARSE_CALLS
----------- ------------- ----------- ------------- -------------------------------------------------- -----------
 2034333845 gbkazctwn2y4p           0             1 insert into tt values(:a,:b)                                 1



相關推薦

ORACLE 變數用法總結

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

oracle變數使用方法總結

在Oracle中,對於一個提交的sql語句,存在兩種可選的解析過程,硬解析和軟解析。 一個硬解析需要經解析,制定執行路徑,優化訪問計劃等步驟。硬解析不僅僅會耗費大量的cpu,更重要的是會佔據重要的閂(latch)資源。唯一使得oracle能夠重複利用執行計劃的方法就是採用繫

Oracle 變數窺探

Bind Peeking是Oracle 9i中引入的新特性,一直持續到Oracle 10g R2。它的作用就是在SQL語句硬分析的時候,檢視一下當前SQL謂詞的值 ,以便生成最佳的執行計劃。而在oracle 9i之前的版本中,Oracle 只根據統計資訊來做出執行計劃。

oracle 變數,索引優缺點

繫結變數 優點: 可以在library cache中共享遊標,避免硬解析以及與之相關的額外開銷 在大批量資料操作時將呈數量級來減少閂鎖的使用,避免閂鎖的競爭 缺點: 繫結變數被使用時,查詢優化器會忽略其具體

ORACLE中對in操作使用變數方法

ORACLE中對in操作使用變數繫結的方法<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />在ORACLE資料庫程式設計中使用變數繫結,可以重用共享池的查詢,最小

檢視oracle中未使用變數的sql語句

資料庫版本:11.2.0.4 查詢語句: with force_mathces as (select l.force_matching_signature mathces, max(l.sql_id || l.child_number) max_sql_

mybatis批量分批次插入oracle資料庫,報ORA-01745: 無效的主機/變數名...

方法一:迴圈呼叫插入單條記錄的方法,效率真心讓人捉急 (3萬條資料,快三分鐘)     public int saveGwghidlist1(List<Gwghid> list) {                  int xh=0;         dele

oracle動態sql以及變數

        實現動態SQL有兩種方式:DBMS_SQL和本地動態SQL(EXECUTE IMMEIDATE) 。 oracle從8代開始就提供了新的執行動態sql的功能:execute immeidate v_sql using *** into ***; 本地動態

關於變數關閉的情況,Oracle是如何工作的?

關於如果繫結變數窺探被關閉了,oracle 會怎麼處理的呢?是每次都硬解析還是這樣處理? 首先介紹下繫結變數窺探: 使用SQL首次執行時的值來生成執行計劃。後續再次執行該SQL語句則使用首次執行計劃來執行。 測試版本:Oracle 12.1.0.2

oracle筆記--case的使用和變數

oracle裡的case功能非常強大, 簡單的用法: select  CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END from student; 還沒有當做預處理去使用 select

oracle 使用udev磁碟方法

scsi_id命令發出一個SCSI INQUIRY指令給裝置,訪問vital product data (VPD)頁0x83的資料,那裡包含裝置的WWID和其他的資訊,或者頁0x80的資料,那裡包含單元序列號(unit serial number)。 scsi_id命令的執行結果(一長串字元)是裝置的WW

oracle開發過程中儘量使用變數

在儲存過程或者java程式使用sql的過程中,儘量使用繫結變數。否則硬解析太多,比較拖效能。 下面查詢只是空格多了幾個。 SQL> select * from ml_1234 where a

動態建立一組按鈕,併為其變數引數事件方法

做專案時,遇到一個比較奇怪的需求,需要用highChart作圖,但是由於橫座標是公司的部分職級的人員,且人員數目較多,這樣就會造成作出來的圖好長, 在有限的螢幕上顯示不全。於是客戶要求,可以將所有人員根

oracle變數的使用

不使用繫結變數而使用硬編碼是oracle效能問題的主要原因和可伸縮性的主要障礙而且這種障礙是除了使用繫結變數以外很難改變的!下面根據一個簡單的試驗來檢視硬編碼與使用繫結變數對效能的影響:在一個查詢中我們可以使用兩種方式:比如查詢個人編號:select * from ac01

Oracle面對“資料傾斜列使用變數”場景的解決方案

1.背景知識介紹 2.構造測試用例 3.場景測試 4.總結 1.背景知識介紹     我們知道,Oracle在傳統的OLTP(線上事務處理)類系統中,強烈推薦使用繫結變數,這樣可以有效的減少硬解析從而增加系統的併發處理能力。甚至在有些老舊系統,由於在開始開發階段缺乏

Oracle SQL調優之變數用法簡介

最近在看《基於Oracle的SQL優化一書》,並做了筆記,作者的個人部落格:[http://www.dbsnake.net/](http://www.dbsnake.net/) @[toc] ## 一、SQL執行過程簡介 繼上一篇部落格Oracle的cursor學習筆記:[Oracle的遊標Cursor原理

SQL Profiles的force_match引數在不改變程式碼的情況下解決沒有使用變數的問題

How To Use SQL Profiles for Queries Using Different Literals Using the Force_Match Parameter of DBMS_SQLTUNE.ACCEPT_SQL_PROFILE (Doc ID 1253696.1)

降低oracle高水位線方法總結(包括驗證結果)

1. 執行表重建指令 alter table table_name move(驗證不可行,不降低水位線,但可釋放表空間) 當你建立了一個物件如表以後,不管你有沒有插入資料,它都會佔用一些塊,ORACLE也會給它分配必要的空間.同樣,用ALTER TABLE MOVE釋放自由空間後,還是保留了一些

android data binding jetpack III 一個方法

第三篇  給view繫結一下方法響應。  (補充:1.被繫結的方法必須是public的。      1.繫結方法可以用主語法。也可以用以下雙冒號方式“::”    android:onClick="@{presenter::onClick}" ) 第一步:定義個響應

Oracle: 環境變數相關總結,Toad關於OCI的配置,PLSQL等配置

環境變數快速示例 在環境變數中,有效的環境變數有如下 ORACLE_HOME ORACLE_SID SQLPATH TNS_ADMIN NLS_LANG 其中ORACLE_HOME環境變數允許指向多個instant-client ,需要注意的是,對於pls