您的位置:首页 > 其它

绑定变量窥探(bind peeking)--什么使执行计划不准

2012-11-12 19:12 573 查看
       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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: