Oracle Bind Variable


    Oracle Bind Variable(綁定變量)就其本質來說就是把本來需要Oracle做硬解析的SQL變成了軟解析,以減少Oracle花費在SQL解析上的時間和資源。

    我們設想一個銀行ATM機系統,這是一個比較典型的OLTP系統,用戶分別在不同的ATM機上做操作,其實所有的用戶做的操作基本上是相同的,主要是這樣3種,查詢,取款,存款。

    對於查詢,發出的查詢大概就是這樣的一條SQL:

         Select account_value from account_info where acount_name = 'myname';

    而對於取款和存款,對於數據庫來說是一樣的,不過是修改當前賬戶上余額的一個數值:

         update account_info set account_value = new_value where account_name = 'myname';

    比如我們有兩個用戶A和B都分別查詢了自己的余額,並且各自取了500塊錢和1000塊錢,那么他們各自發出的SQL分別是:

用戶A:

1 select account_value from account_info where acount_name = 'A';
2 update account_info set account_value = account - 500 where account_name = 'A';

用戶B:

1 select account_value from account_info where acount_name = 'B';
2 update account_info set account_value = acount_value - 1000 where account_name = 'B';

    我們看到,其實他們兩個人發出的2條SQL,除了各自的謂詞條件不同之外,其他的都相同,包括語法,操作的對象,權限等,所以如果我們拿一個共同的東西來代替他們的謂詞條件,那么這條SQL豈不是就變成了1條SQL,比如:

1 select account_value from account_info where acount_name = :X;
2 update account_info set account_value = acount_value - 1000 where account_name = :Y;

    通過上面的一個變量替代,我們就將兩條SQL變成了1條SQL了,這樣的好處在於,Oracle只需對每一種SQL做一次硬解析,后續類似的SQL(指的是只有謂詞條件不同的SQL)都使用這條SQL產生的執行計划,這樣就可以大大降低數據庫花費在SQL解析上的資源開銷。
下面的例子對比了一下一條SQL被執行10000次時,綁定變量和非綁定變量在資源消耗上的情況:

  1 SQL> show parameter cursor_sharing;
  2 
  3 NAME                     TYPE     VALUE
  4 ------------------------------------ ----------- ------------------------------
  5 cursor_sharing                 string     EXACT
  6 SQL> create table jack as select * from dba_objects;
  7 
  8 Table created.
  9 
 10 SQL> alter session set sql_trace = true;
 11 
 12 Session altered.
 13 
 14 SQL> begin
 15   2      for x in 1..10000 loop
 16   3    execute immediate 'select * from jack where object_id=:x' using x;
 17   4     end loop;
 18   5  end;
 19   6  /
 20 
 21 PL/SQL procedure successfully completed.
 22 
 23 SQL> alter session set sql_trace = false;
 24 
 25 Session altered.
 26 
 27 SQL> @showtrace;
 28 
 29 trace_file_name
 30 --------------------------------------------------------------------------------
 31 /u01/app/oracle/diag/rdbms/yft2/YFT2/trace/yft2_ora_5865.trc
 32 
 33 [oracle@node2 ~]$ tkprof /u01/app/oracle/diag/rdbms/yft2/YFT2/trace/YFT2_ora_5865.trc out.txt sys=no
 34 
 35 TKPROF: Release 11.2.0.1.0 - Development on Sat Feb 2 15:33:16 2013
 36 
 37 Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.
 38 
 39 
  ----trace文件信息----
40
[oracle@node2 ~]$ cat out.txt 41 42 TKPROF: Release 11.2.0.1.0 - Development on Sat Feb 2 15:33:16 2013 43 44 Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved. 45 46 Trace file: /u01/app/oracle/diag/rdbms/yft2/YFT2/trace/YFT2_ora_5865.trc 47 Sort options: default 48 49 ******************************************************************************** 50 count = number of times OCI procedure was executed 51 cpu = cpu time in seconds executing 52 elapsed = elapsed time in seconds executing 53 disk = number of physical reads of buffers from disk 54 query = number of buffers gotten for consistent read 55 current = number of buffers gotten in current mode (usually for update) 56 rows = number of rows processed by the fetch or execute call 57 ******************************************************************************** 58 59 SQL ID: 1hgzr5xxpmt7h 60 Plan Hash: 0 61 alter session set sql_trace = true 62 63 64 call count cpu elapsed disk query current rows 65 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 66 Parse 0 0.00 0.00 0 0 0 0 67 Execute 1 0.00 0.00 0 0 0 0 68 Fetch 0 0.00 0.00 0 0 0 0 69 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 70 total 1 0.00 0.00 0 0 0 0 71 72 Misses in library cache during parse: 0 73 Misses in library cache during execute: 1 74 Optimizer mode: ALL_ROWS 75 Parsing user id: 87 76 ******************************************************************************** 77 78 begin 79 for x in 1..10000 loop 80 execute immediate 'select * from jack where object_id=:x' using x; 81 end loop; 82 end; 83 84 call count cpu elapsed disk query current rows 85 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 86 Parse 1 0.00 0.00 0 0 0 0 87 Execute 1 1.05 1.07 0 0 0 1 88 Fetch 0 0.00 0.00 0 0 0 0 89 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 90 total 2 1.06 1.07 0 0 0 1 91 92 Misses in library cache during parse: 1 93 Optimizer mode: ALL_ROWS 94 Parsing user id: 87 95 ******************************************************************************** 96 97 SQL ID: ba3vgakkn7zz5 98 Plan Hash: 949574992 99 select * 100 from 101 jack where object_id=:x 102 103 104 call count cpu elapsed disk query current rows 105 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 106 Parse 1 0.00 0.00 0 0 0 0 107 Execute 10000 0.07 0.09 0 1 0 0 108 Fetch 0 0.00 0.00 0 0 0 0 109 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 110 total 10001 0.07 0.09 0 1 0 0 111 112 Misses in library cache during parse: 1 113 Optimizer mode: ALL_ROWS 114 Parsing user id: 87 (recursive depth: 1) 115 116 Rows Row Source Operation 117 ------- --------------------------------------------------- 118 0 TABLE ACCESS FULL JACK (cr=0 pr=0 pw=0 time=0 us cost=287 size=2484 card=12) 119 120 ******************************************************************************** 121 122 SQL ID: brjr07qkfmgww 123 Plan Hash: 4286693666 124 SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE 125 NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false') 126 NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),0), NVL(SUM(C2),0) 127 FROM 128 (SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("JACK") FULL("JACK") 129 NO_PARALLEL_INDEX("JACK") */ 1 AS C1, CASE WHEN "JACK"."OBJECT_ID"=:B1 THEN 130 1 ELSE 0 END AS C2 FROM "JACK" SAMPLE BLOCK (6.000000 , 1) SEED (1) "JACK") 131 SAMPLESUB 132 133 134 call count cpu elapsed disk query current rows 135 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 136 Parse 1 0.00 0.00 0 0 0 0 137 Execute 1 0.00 0.00 0 0 0 0 138 Fetch 1 0.01 0.01 265 60 0 1 139 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 140 total 3 0.02 0.02 265 60 0 1 141 142 Misses in library cache during parse: 1 143 Misses in library cache during execute: 1 144 Optimizer mode: ALL_ROWS 145 Parsing user id: 87 (recursive depth: 2) 146 147 Rows Row Source Operation 148 ------- --------------------------------------------------- 149 1 SORT AGGREGATE (cr=60 pr=265 pw=0 time=0 us) 150 3817 TABLE ACCESS SAMPLE JACK (cr=60 pr=265 pw=0 time=71104 us cost=19 size=128650 card=5146) 151 152 ******************************************************************************** 153 154 SQL ID: 988n7wn97ptgf 155 Plan Hash: 0 156 alter session set sql_trace = false 157 158 159 call count cpu elapsed disk query current rows 160 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 161 Parse 1 0.00 0.00 0 0 0 0 162 Execute 1 0.00 0.00 0 0 0 0 163 Fetch 0 0.00 0.00 0 0 0 0 164 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 165 total 2 0.00 0.00 0 0 0 0 166 167 Misses in library cache during parse: 1 168 Optimizer mode: ALL_ROWS 169 Parsing user id: 87 170 171 172 173 ******************************************************************************** 174 175 OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS 176 177 call count cpu elapsed disk query current rows 178 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 179 Parse 2 0.00 0.00 0 0 0 0 180 Execute 3 1.05 1.07 0 0 0 1 181 Fetch 0 0.00 0.00 0 0 0 0 182 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 183 total 5 1.06 1.07 0 0 0 1 184 185 Misses in library cache during parse: 2 186 Misses in library cache during execute: 1 187 188 189 OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS 190 191 call count cpu elapsed disk query current rows 192 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 193 Parse 3 0.00 0.00 0 0 0 0 194 Execute 10017 0.08 0.09 0 1 0 0 195 Fetch 17 0.01 0.01 265 92 0 1 196 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 197 total 10037 0.10 0.11 265 93 0 1 198 199 Misses in library cache during parse: 3 200 Misses in library cache during execute: 2 201 202 10004 user SQL statements in session. 203 16 internal SQL statements in session. 204 10020 SQL statements in session. 205 ******************************************************************************** 206 Trace file: /u01/app/oracle/diag/rdbms/yft2/YFT2/trace/YFT2_ora_5865.trc 207 Trace file compatibility: 11.1.0.7 208 Sort options: default 209 210 1 session in tracefile. 211 10004 user SQL statements in trace file. 212 16 internal SQL statements in trace file. 213 10020 SQL statements in trace file. 214 6 unique SQL statements in trace file. 215 60178 lines in trace file. 216 70 elapsed seconds in trace file.
從上面的trace文件信息中可以得到:
執行時間:1.17+0.11=1.18秒
CPU時間:1.06+0.10=1.16秒
分析次數:5次
執行次數:10020次

     上面是一個綁定變量的SQL的執行情況,下面是一個未綁定變量的SQL:

  1 SQL> alter system flush shared_pool;
  2 
  3 System altered.
  4 
  5 SQL> alter system flush shared_pool;
  6 
  7 System altered.
  8 
  9 SQL> alter session set sql_trace = true;
 10 
 11 Session altered.
 12 
 13 SQL> begin
 14   2     for x in 1..10000 loop
 15   3       execute immediate 'select * from jack where object_id = '||x;
 16   4    end loop;
 17   5  end;
 18   6  /
 19 
 20 PL/SQL procedure successfully completed.
 21 
 22 SQL> alter session set sql_trace = false;
 23 
 24 Session altered.
 25 
 26 SQL> @showtrace
 27 
 28 trace_file_name
 29 --------------------------------------------------------------------------------
 30 /u01/app/oracle/diag/rdbms/yft2/YFT2/trace/yft2_ora_5959.trc
 31 
 32 [oracle@node2 ~]$ tkprof /u01/app/oracle/diag/rdbms/yft2/YFT2/trace/YFT2_ora_5959.trc out.txt sys=no
 33 
 34 TKPROF: Release 11.2.0.1.0 - Development on Sat Feb 2 15:51:09 2013
 35 
 36 Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.
 37 
 38 
  ----trace文件信息----
39
SQL ID: f1d5d4pw64fw9 40 Plan Hash: 949574992 41 select * 42 from 43 jack where object_id = 1 44 45 46 call count cpu elapsed disk query current rows 47 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 48 Parse 1 0.00 0.01 0 2 0 0 49 Execute 1 0.00 0.00 0 0 0 0 50 Fetch 0 0.00 0.00 0 0 0 0 51 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 52 total 2 0.00 0.01 0 2 0 0 53 54 Misses in library cache during parse: 1 55 Optimizer mode: ALL_ROWS 56 Parsing user id: 87 (recursive depth: 1) 57 58 Rows Row Source Operation 59 ------- --------------------------------------------------- 60 0 TABLE ACCESS FULL JACK (cr=0 pr=0 pw=0 time=0 us cost=287 size=2484 card=12) 61 62 ******************************************************************************** 63 64 SQL ID: 60g8qk8gv4363 65 Plan Hash: 949574992 66 select * 67 from 68 jack where object_id = 2 69 70 71 call count cpu elapsed disk query current rows 72 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 73 Parse 1 0.00 0.00 0 1 0 0 74 Execute 1 0.00 0.00 0 0 0 0 75 Fetch 0 0.00 0.00 0 0 0 0 76 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 77 total 2 0.00 0.00 0 1 0 0 78 79 Misses in library cache during parse: 1 80 Optimizer mode: ALL_ROWS 81 Parsing user id: 87 (recursive depth: 1) 82 83 Rows Row Source Operation 84 ------- --------------------------------------------------- 85 0 TABLE ACCESS FULL JACK (cr=0 pr=0 pw=0 time=0 us cost=287 size=2484 card=12) 86 87 ******************************************************************************** 88 89 SQL ID: 1833z5rb1h922 90 Plan Hash: 949574992 91 select * 92 from 93 jack where object_id = 3 94 95 96 call count cpu elapsed disk query current rows 97 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 98 Parse 1 0.00 0.00 0 1 0 0 99 Execute 1 0.00 0.00 0 0 0 0 100 Fetch 0 0.00 0.00 0 0 0 0 101 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 102 total 2 0.00 0.00 0 1 0 0 103 104 Misses in library cache during parse: 1 105 Optimizer mode: ALL_ROWS 106 Parsing user id: 87 (recursive depth: 1) 107 108 Rows Row Source Operation 109 ------- --------------------------------------------------- 110 0 TABLE ACCESS FULL JACK (cr=0 pr=0 pw=0 time=0 us cost=287 size=2484 card=12) 111 112 ******************************************************************************** 113 114 。。。。。。 115 116 ******************************************************************************** 117 118 SQL ID: d8xbnmha6p8b7 119 Plan Hash: 949574992 120 select * 121 from 122 jack where object_id = 10000 123 124 125 call count cpu elapsed disk query current rows 126 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 127 Parse 1 0.00 0.00 0 1 0 0 128 Execute 1 0.00 0.00 0 0 0 0 129 Fetch 0 0.00 0.00 0 0 0 0 130 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 131 total 2 0.00 0.00 0 1 0 0 132 133 Misses in library cache during parse: 1 134 Optimizer mode: ALL_ROWS 135 Parsing user id: 87 (recursive depth: 1) 136 137 Rows Row Source Operation 138 ------- --------------------------------------------------- 139 0 TABLE ACCESS FULL JACK (cr=0 pr=0 pw=0 time=0 us cost=287 size=2484 card=12) 140 141 ******************************************************************************** 142 143 SQL ID: 988n7wn97ptgf 144 Plan Hash: 0 145 alter session set sql_trace = false 146 147 148 call count cpu elapsed disk query current rows 149 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 150 Parse 1 0.00 0.00 0 0 0 0 151 Execute 1 0.01 0.01 0 0 0 0 152 Fetch 0 0.00 0.00 0 0 0 0 153 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 154 total 2 0.01 0.01 0 0 0 0 155 156 Misses in library cache during parse: 1 157 Optimizer mode: ALL_ROWS 158 Parsing user id: 87 159 160 161 162 ******************************************************************************** 163 164 OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS 165 166 call count cpu elapsed disk query current rows 167 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 168 Parse 2 0.00 0.00 0 0 0 0 169 Execute 3 2.08 2.21 0 257 0 1 170 Fetch 0 0.00 0.00 0 0 0 0 171 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 172 total 5 2.09 2.22 0 257 0 1 173 174 Misses in library cache during parse: 2 175 Misses in library cache during execute: 1 176 177 178 OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS 179 180 call count cpu elapsed disk query current rows 181 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 182 Parse 20073 11.90 12.28 0 10001 0 0 183 Execute 20141 0.54 0.59 0 0 0 0 184 Fetch 10506 12.23 12.69 1 600411 0 11215 185 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- 186 total 50720 24.69 25.58 1 610412 0 11215 187 188 Misses in library cache during parse: 10020 189 Misses in library cache during execute: 20 190 191 20003 user SQL statements in session. 192 141 internal SQL statements in session. 193 20144 SQL statements in session. 194 ******************************************************************************** 195 Trace file: /u01/app/oracle/diag/rdbms/yft2/YFT2/trace/YFT2_ora_5959.trc 196 Trace file compatibility: 11.1.0.7 197 Sort options: default 198 199 1 session in tracefile. 200 20003 user SQL statements in trace file. 201 141 internal SQL statements in trace file. 202 20144 SQL statements in trace file. 203 10020 unique SQL statements in trace file. 204 161613 lines in trace file. 205 83 elapsed seconds in trace file.
上面的trace文件中得到:
執行時間:2.22+25.58=27.8秒
CPU時間:2.09+24.69=26.78秒
分析次數:20075次
執行次數:20144次

   兩種情況對比的結果顯示,綁定變量SQL的資源消耗要遠遠少於未綁定變量SQL的資源消耗,SQL執行的次數越多,這種差距將越明顯,未綁定變量SQL的資源主要消耗在產生的遞歸SQL上,這些SQL主要是在對SQL語句做硬分析時使用的。

   如果我們讓所有的用戶在數據庫操作時傳給Oracle的都是這樣一個由變量代替常量的SQL,那么Oracle只需要硬分析最早的一條SQL就可以了,其它后續的SQL都可以直接使用第一條SQL的執行計划來執行,只在SQL執行的時候,Oracle再使用每個用戶的實際謂詞條件來替換變量,這樣就省卻了前面很耗資源的硬分析過程。

   試想,當一個數據庫有成千上萬或者更多的用戶同時執行這樣的SQL,而Oracle只做一次硬分析,之后只對每個SQL做執行操作,那必將極大地減輕數據庫資源開銷。

這就是變量綁定的由來,它並不神秘,不過是拿一個變量來代替謂詞常量,讓Oracle每次對用戶發來的SQL做Hash運算時,運算出的結果都是同樣的Hash值,於是將所有的用戶發送的SQL看作是同一個SQL來對待而已。

   最后可以看一下哪種環境下適合綁定變量:《關於為什么說OLTP必須要求變量綁定而OLAP不應該綁定變量的原因》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM