最近被很多朋友问起关于绑定变量窥探的问题:
讨论的是如果绑定变量窥探被关闭了,oracle 会怎么处理,
是每次都硬解析还是这样处理?
首先介绍下什么是绑定变量窥探?
使用SQL首次运行时的值来生成执行计划。后续再次运行该SQL语句则使用首次执行计划来执行。
影响的版本:Oracle 9i, Oracle 10g
对于绑定变量列中的特殊值或非均匀分布列上的绑定变量会造成非高效的执行计划被选择并执行。
要注意的是,Bind Peeking只发生在硬分析的时候,即SQL被第一次执行的时候,之后的变量将不会在做peeking。我们可以看出,Bind
peeking并不能最终解决不同谓词导致选择不同执行计划的问题,它只能让SQL第一次执行的时候,执行计划选择更加准确,并不能帮助OLAP
系统解决绑定变量导致执行计划选择错误的问题。这也是OLAP不应该使用绑定变量的一个原因。在第一次解析SQL时,按照窥探变量的值生成执行计划,以后这样的SQL都按照这个执行。隐藏参数_optim_peek_user_binds=true则启用绑定变量窥探,否则CBO认为统计列是均匀的。
其次对这个问题分析处理思路如下:
这里我认为首先如果绑定变量窥探关闭了,那么是否有直方图对执行计划就影响不大了,因为oracle都把它作为一个参数带入,而不会去查看他的值,是的,连第一次都不查看。如果不窥探,那么按照正常的值进行成本分析,然后oracle不考虑具体的值,把这个值作为一个均匀分布带入。
如果窥探了,仅仅是第一次会去窥探,试想下,如果每次都窥探,就变成硬解析了,
硬解析对oltp有多大的危害,这里就不讨论,有兴趣的朋友可以去看下绑定变量那部分内容:
下面我简单的用实验说明下这个问题:
结论1: 绑定变量窥探一定要有直方图的时候才会起效果,否则一样窥探没效果。
SQL> create table daodao as select object_id,object_name from dba_objects;
SQL> create index daodao_index on daodao(object_id);
SQL> insert into daodao select '0' ,0 from dba_objects;
Commit; ----在这里已经构造出object_id =0 占了一半的数据量:
SQL>begin
dbms_stats.gather_table_stats(
ownname=> user,
tabname=>'DAODAO',
estimate_percent=>100,
method_opt=>'for all columns size 1'); --注意这里没有分析直方图:
end;
/
SQL> select table_name,column_name,num_distinct,histogram from dba_tab_col_statistics where table_name='DAODAO' and column_name='OBJECT_ID';
TABLE_NAME COLUMN_NAME NUM_DISTINCT HISTOGRAM
------------------------------ ------------------------------ ------------ ---------------
DAODAO OBJECT_ID 50745 NONE
从这里看出直方图是没有分析的:
如果这个时候执行
select * from dba_objects where object_id = 0 ,大家认为会走什么?
肯定会走索引:
为什么呢?
SQL> var a number;
SQL> execute :a:=0;
PL/SQL procedure successfully completed.
SQL> select count(object_name) from daodao where object_id=:a;
COUNT(OBJECT_NAME)
------------------
50745
SQL> select * from table(dbms_xplan.display_cursor());
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID cqh9z6m8u1035, child number 0
-------------------------------------
select count(object_name) from daodao where object_id=:a
Plan hash value: 1136156284
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | SORT AGGREGATE | | 1 | 16 | | |
| 2 | TABLE ACCESS BY INDEX ROWID| DAODAO | 2 | 32 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | DAODAO_INDEX | 2 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_ID"=:A)
20 rows selected.
实际上确实是走索引,主要原因是虽然使用了绑定变量窥探,但是由于没有直方图,即使窥探了,也是采用均匀分布分析,走索引的执行计划。
那现在加入有直方图,我们继续试验下:
SQL> begin
2 dbms_stats.gather_table_stats(
3 ownname=> user,
4 tabname=>'DAODAO',
5 estimate_percent=>100
6 )
7 ;
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> select table_name,column_name,num_distinct,histogram from dba_tab_col_statistics where table_name='DAODAO' and column_name='OBJECT_ID';
TABLE_NAME COLUMN_NAME NUM_DISTINCT HISTOGRAM
------------------------------ ------------------------------ ------------ ---------------
DAODAO OBJECT_ID 50745 HEIGHT BALANCED
有了直方图了,然后继续执行。
SQL> var b number;
SQL> execute :b:=0;
PL/SQL procedure successfully completed.
SQL> select count(object_name) from daodao where object_id=:b;
COUNT(OBJECT_NAME)
------------------
50745
SQL> select * from table(dbms_xplan.display_cursor());
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 1frj18k6608ur, child number 0
-------------------------------------
select count(object_name) from daodao where object_id=:b
Plan hash value: 3103463029
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 66 (100)| |
| 1 | SORT AGGREGATE | | 1 | 16 | | |
|* 2 | TABLE ACCESS FULL| DAODAO | 50345 | 786K| 66 (5)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_ID"=:B)
19 rows selected.
这个时候绑定变量窥探才发挥了他的作用,各位看官明白没?
结论2:关闭了绑定变量窥探,以后每次也是软解析,而且关闭了绑定变量窥探之后,即使你分析了直方图还是执行均匀分布,按照cost计算出成本,然后走oracle认为的执行计划:
(1) 按照上面的结论,继续执行:
SQL> alter session set "_optim_peek_user_binds"=false;
Session altered.
SQL> var d number;
SQL> execute :d:=0;
PL/SQL procedure successfully completed.
SQL> select a.value,b.value from v$sysstat a,v$sysstat b where a.name='parse count (hard)' and b.name='parse count (total)';
VALUE VALUE
---------- ----------
21818 577593
SQL> select count(object_name) from daodao where object_id=:d;
COUNT(OBJECT_NAME)
------------------
50745
SQL> select a.value,b.value from v$sysstat a,v$sysstat b where a.name='parse count (hard)' and b.name='parse count (total)';
VALUE VALUE
---------- ----------
21819 577595
--=记录当前的硬解析次数,实验环境,就我一个单用户操作:
SQL> select count(object_name) from daodao where object_id=:d;
COUNT(OBJECT_NAME)
------------------
50745
SQL> select a.value,b.value from v$sysstat a,v$sysstat b where a.name='parse count (hard)' and b.name='parse count (total)';
VALUE VALUE
---------- ----------
21819 577597
硬解析没有改变,所以关闭了绑定变量,还是使用了软解析:
这个时候object_id这列是有直方图的:
SQL> select table_name,column_name,num_distinct,histogram from dba_tab_col_statistics where table_name='DAODAO' and column_name='OBJECT_ID';
TABLE_NAME COLUMN_NAME NUM_DISTINCT HISTOGRAM
------------------------------ ------------------------------ ------------ ---------------
DAODAO OBJECT_ID 50745 HEIGHT BALANCED
这个时候再执行操作:
SQL> select count(object_name) from daodao where object_id=:d;
COUNT(OBJECT_NAME)
------------------
50745
SQL> select * from table(dbms_xplan.display_cursor());
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 0k0snturu73qm, child number 1
-------------------------------------
select count(object_name) from daodao where object_id=:d
Plan hash value: 1136156284
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | SORT AGGREGATE | | 1 | 16 | | |
| 2 | TABLE ACCESS BY INDEX ROWID| DAODAO | 2 | 32 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | DAODAO_INDEX | 2 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_ID"=:D)
20 rows selected.
看到没有,即使是一半数量的0,还是走索引操作,可见这个时候的绑定变量窥探功能关闭了,Oracle把这个0当成是带入参数了。
总结:
绑定变量窥探功能要在有直方图的列分析里面才能起到第一次的窥探作用,
但是如果你是倾斜列,也会导致执行计划走错,关闭了绑定变量窥探功能,会导致连第一次窥探都没有,后续所有的sql依然会软解析。