繫結變數的使用範圍

wei-xh發表於2010-05-08
我們都知道繫結變數可以減少軟解析。
可是對於表的資料傾斜列,使用繫結變數有個壞處,那就是最佳化器可能會產生效能低下的執行計劃。
對於一個使用繫結變數的SQL語句,第一次執行的時候,最佳化器會使用一個叫做BIND PEEKING的技術,對繫結變數的值進行繫結窺探(BAND PEEKING),來生成執行計劃,以後再執行同樣的語句,會依賴於第一次執行時的執行計劃。
對於資料傾斜列,由於BIND PEEKING的特點,可能會產生效能非常低下的執行計劃。
下面看看測試情況:
SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE    10.2.0.1.0      Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
1)不使用繫結變數的情況。
測試表tab,其中列B為傾斜列。
SQL> desc tab;
名稱    是否為空?                型別
  a                             number
  b                             number
SQL> select b,count(1) from tab group by b;


         B   COUNT(1)
---------- ----------
         1          1
         2          1
         3          1
         4          1
         5       9991
      9996          1
      9997          1
      9998          1
      9999          1
     10000          1
可以看出列值等於5的佔了絕大數。

create index ind_tab_b on tab(b);
分析表:
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(OWNNAME    => 'SCOTT',
                                TABNAME    => 'TAB',
                                CASCADE    => TRUE);
END;

然後執行查詢:
SQL> select * from tab where b=1;
         A          B
---------- ----------
         1          1

已用時間:  00: 00: 00.00
SQL> select * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------
--------
SQL_ID  8vjf9k7jrfbh5, child number 0
-------------------------------------
select * from tab where b=:"SYS_B_0"

Plan hash value: 1668701379
------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |       |       |     2 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB  |     1 |     6 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | SS   |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("B"=:SYS_B_0)

已選擇19行。
已用時間:  00: 00: 00.17

SQL> select * from tab where b=5;
已用時間:  00: 00: 00.00

執行計劃
----------------------------------------------------------
Plan hash value: 1995730731

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  9991 | 59946 |     6   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TAB  |  9991 | 59946 |     6   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("B"=5)

可以看到產生了我們預想的正確的執行計劃。


[ 本帖最後由 wei-xh 於 2010-5-8 19:49 編輯 ]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22034023/viewspace-662254/,如需轉載,請註明出處,否則將追究法律責任。

相關文章