綁定變量窺探(bind peeking)--什麼使執行計劃不準

OLTP中爲了解決SQL語句硬解析的問題,使用了綁定變量,在oracle 10g版本中,這樣帶來一個問題,每次SQL的執行計劃可能不是最優的,正式環境和測試環境上的執行計劃不一致。

      爲什麼會產生這種問題:在執行含有綁定變量的查詢語句時,完成解析和最優化操作之後對綁定變量進行綁定,這以爲着在實現最優化操作時無法使用綁定變量列的統計信息。爲了解決這個問題,數據庫使用了窺探技術,在第一次解析SQL時,按照窺探變量的值生成執行計劃,以後這樣的SQL都按照這個執行。隱藏參數_optim_peek_user_binds=true則啓用綁定變量窺探,否則CBO認爲統計列是均勻的。下面來做個實驗,注意的是 set autotrace這個玩意產生的執行計劃可能不準:

SQL> create table test as select * from all_objects;

SQL> create index ind_object_name on TEST (object_name);

SQL> exec dbms_stats.gather_table_stats(user,'TEST',cascade=>true);

SQL> update test set object_name='aaa';

SQL> commit;

SQL> update test set object_name='bbb' where object_id=20;

SQL> commit;

SQL> select count(1) from test where object_name='aaa';

 COUNT(1)

----------

    50653

SQL> select count(1) from test where object_name='bbb';

 COUNT(1)

----------

        1

SQL> var ccc varchar2(10);

SQL> exec :ccc:='aaa';--按道理說是全表掃描,結果也是全表掃描

SQL> set autotrace exp

SQL> select * from test where object_name=:ccc;

SQL> set autotrace off;

SQL> select hash_value, child_number

 2    from v$sql

 3   where sql_text = 'select * from test where object_name=:ccc';

HASH_VALUE CHILD_NUMBER

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

2373399249           0

SQL> select * from table(dbms_xplan.display_cursor(2373399249,0));

| Id | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|  0 | SELECT STATEMENT  |      |       |       |   163 (100)|          |

|* 1 |  TABLE ACCESS FULL| TEST | 50654 |  3611K|   163   (4)| 00:00:02 |

PLAN_TABLE_OUTPUT

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

Predicate Information (identified by operation id):

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

  1 - filter("OBJECT_NAME"=:CCC)

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

SQL> exec :ccc:='bbb';--按道理說是索引掃描,但是結果卻是全表掃描

SQL> set autotrace exp

SQL> select * from test where object_name=:ccc;

SQL> set autotrace off;

SQL> select hash_value, child_number

 2    from v$sql

 3   where sql_text = 'select * from test where object_name=:ccc';

HASH_VALUE CHILD_NUMBER

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

2373399249           0

SQL> select * from table(dbms_xplan.display_cursor(2373399249,0));

PLAN_TABLE_OUTPUT

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

| Id | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|  0 | SELECT STATEMENT  |      |       |       |   163 (100)|          |

|* 1 |  TABLE ACCESS FULL| TEST | 50654 |  3611K|   163   (4)| 00:00:02 |

PLAN_TABLE_OUTPUT

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

Predicate Information (identified by operation id):

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

  1 - filter("OBJECT_NAME"=:CCC)

SQL> alter system flush shared_pool;--清理share_pool

SQL> exec :ccc:='bbb';--按道理說是索引掃描,結果也是索引掃描

SQL> set autotrace exp

SQL> select * from test where object_name=:ccc;

SQL> select hash_value, child_number

 2    from v$sql

 3   where sql_text = 'select * from test where object_name=:ccc';

HASH_VALUE CHILD_NUMBER

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

2373399249           0

SQL> select * from table(dbms_xplan.display_cursor(2373399249,0));

PLAN_TABLE_OUTPUT

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

| Id | Operation | Name    | Rows  | Bytes | Cost (%CPU)| Time     |

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

|   0 | SELECT STATEMENT   |    |       |    |     2 (100)|          |

|  1 |  TABLE ACCESS BY INDEX ROWID| TEST  |  1 | 73 |  2   (0)| 00:00:01 |

|* 2 |   INDEX RANGE SCAN | IND_OBJECT_NAME | 1 |  |1   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

  2 - access("OBJECT_NAME"=:CCC)

SQL> exec :ccc:='aaa';--按道理說是全表掃描,但結果卻是索引掃描

SQL> select * from test where object_name=:ccc;

SQL> select hash_value, child_number

 2    from v$sql

 3   where sql_text = 'select * from test where object_name=:ccc';

HASH_VALUE CHILD_NUMBER

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

2373399249           0

SQL> select * from table(dbms_xplan.display_cursor(2373399249,0));

PLAN_TABLE_OUTPUT

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

| Id | Operation | Name  | Rows  | Bytes | Cost (%CPU)| Time     |

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

|  0 | SELECT STATEMENT  |    |    |       |     2 (100)|          |

|  1 |  TABLE ACCESS BY INDEX ROWID| TEST | 1 |    73 |   2   (0)| 00:00:01 |

|* 2 |   INDEX RANGE SCAN  | IND_OBJECT_NAME |   1 |  |1   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

  2 - access("OBJECT_NAME"=:CCC)


http://blog.csdn.net/stevendbaguo/article/details/8175633

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章