柱状图(Histogram),绑定变量,bind peeking,cursor_sharing 之间的关系2 绑定变量与柱状图...

前面讨论了有了柱状图的统计信息的时候,对于分布不均衡的列,如果没有使用绑定变量,CBO将会选择正确的执行计划,下面来谈谈对于分布不均衡的列,使用了绑定变量,不收集柱状图统计信息,收集了柱状图统计信息分别会发生什么情况。

本测试同样使用TEST表,表结构和内容请看前一篇内容

在不收集柱状图统计信息的情况下:

session 1中

SQL> exec dbms_stats.gather_table_stats('robinson','test',method_opt=>'for columns size 1 status');

PL/SQL 过程已成功完成。

----将size 置为1,可以删除柱状图统计信息

session 2中

SQL> alter system flush shared_pool;

系统已更改。

session 1中

SQL> variable a varchar2(20);
SQL> exec :a:='UNKONWN';

PL/SQL 过程已成功完成。

SQL> set autot trace

SQL> select owner from test where status=:a;

已选择12行。


执行计划
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 16639 | 211K| 142 (3)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| TEST | 16639 | 211K| 142 (3)| 00:00:02 |
--------------------------------------------------------------------------

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

1 - filter("STATUS"=:A)

此处我没有贴上统计信息
SQL> set autot off
SQL> select operation,options,object_name,id,parent_id,cost from v$sql_plan where object_name='TEST';

OPERATION OPTIONS OBJECT_NAME ID
------------------------------------------------------------ ------------------------------------------------------------ ------------------------------ ----
TABLE ACCESS FULL TEST 1

查看V$sql_plan是为了验证行我们通过autotrace看到的执行计划是否与真实的执行计划一样,此处一样

由此可见,在没有柱状图统计信息的情况下,使用绑定变量的执行计划与不使用绑定变量的执行计划一样,CBO都选择了错误(不是最优)的执行计划。

现在收集柱状图的统计信息

SQL> exec dbms_stats.gather_table_stats('robinson','test',method_opt=>'for columns size 10 status');

PL/SQL 过程已成功完成。

SQL> set autot trace

SQL> select owner from test where status=:a;

已选择12行。


执行计划
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 24959 | 316K| 142 (3)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| TEST | 24959 | 316K| 142 (3)| 00:00:02 |
--------------------------------------------------------------------------

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

1 - filter("STATUS"=:A)

SQL> select operation,options,object_name,id,parent_id,cost,plan_hash_value from v$sql_plan where object_name='TEST';

OPERATION OPTIONS OBJECT_NAM ID PARENT_ID COST PLAN_HASH_VALUE
-------------------- ---------- ---------- ---------- ---------- ---------- ---------------
TABLE ACCESS FULL TEST 1 0 142 1357081020
TABLE ACCESS FULL TEST 2 1 141 1950795681
TABLE ACCESS SAMPLE TEST 2 1 21 3141299468

收集了柱状图统计信息之后还是没有走索引

session 2中

SQL> alter system flush shared_pool;

系统已更改。

session 1中

SQL> select owner from test where status=:a;

已选择12行。


执行计划
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 24959 | 316K| 142 (3)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| TEST | 24959 | 316K| 142 (3)| 00:00:02 |
--------------------------------------------------------------------------

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

1 - filter("STATUS"=:A)

SQL> set autot off
SQL> select operation,options,object_name,id,parent_id,cost,plan_hash_value from v$sql_plan where object_name='TEST';

OPERATION OPTIONS OBJECT_NAM ID PARENT_ID COST PLAN_HASH_VALUE
-------------------- ---------- ---------- ---------- ---------- ---------- ---------------
TABLE ACCESS BY INDEX ROWID TEST 1 0 2 3251734315
为什么 AUTOTRACE 和v$sql_plan查出来的执行计划不一样?,这点不能明白,不过这个时候就只能相信v$sql_plan了

事实上这个时候是走了索引的,我们通过autotrace看到的执行计划是错误的

SQL> exec :a:='VALID';

PL/SQL 过程已成功完成。

SQL> set autot trace
SQL> select owner from test where status=:a;

已选择26942行。


执行计划
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 24959 | 316K| 142 (3)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| TEST | 24959 | 316K| 142 (3)| 00:00:02 |
--------------------------------------------------------------------------

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

1 - filter("STATUS"=:A)

SQL> set autot off
SQL> select operation,options,object_name,id,parent_id,cost,plan_hash_value from v$sql_plan where object_name='TEST';

OPERATION OPTIONS OBJECT_NAM ID PARENT_ID COST PLAN_HASH_VALUE
-------------------- ---------- ---------- ---------- ---------- ---------- ---------------
TABLE ACCESS BY INDEX ROWID TEST 1 0 2 3251734315

由此可见AUTOTRACE显示执行计划也是错误的,此处通过观察发现V$SQL_PLAN里面执行计划也没有改变,但是此处选择了26942行,不该走索引,而且COST居然也是2,此处发现AUTOTRACE 和v$sql_plan都有问题,不过可以肯定的是这个时候没有走全表扫描,而是走的第一次硬解析的时候走的索引范围扫描。

事实上引起这个问题的原因就是bind peeking(绑定窥视)

BIND PEEKING:如果收集了柱状图统计信息,并且使用了绑定变量,在第一次硬解析的时候CBO就会执行BIND PEEKING,以便选择最佳的执行计划,再次执行的时候就不会bind peeking了,始终要记住bind peeking发生的条件:硬解析,存在柱状图,使用了绑定变量或者设置cursor_sharing=similar,下一篇就专门讨论(cursor_sharing=similar)这个问题。

通过实验基本上知道了这个事实:当列分布很倾斜的时候,如果对该列使用了绑定变量,如果不收集柱状图统计信息,那么ORACLE按照全表扫描检索,如果收集了柱状图统计信息,在第一次硬解析的时候CBO会考虑柱状图,选择走索引或者走全表扫描,一旦确定了执行计划,那么第二次执行该SQL,就会利用原来生成的执行计划,而不会去选择最优的执行计划。

就像上面的例子:检索status 为UNKONWN的时候应该走index range scan,而检索status为VALID的时候应该走FULL TABLE SCAN,

但是如果第一次查询STATUS 为UNKONWN ,走了index range scan,这个时候CBO选择正确,但是下一次查询status为VALID的时候应该走full table scan,然后CBO依然选择了index range scan,这个时候CBO选择错误执行计划,而且查看autotrace的执行计划显示有问题,查看v$sql_plan cost有问题.呵呵我应该用10046再追踪一下。

不过可以得到2个提示:1绑定变量并不是在所有情况下都可以提高效率,当然绝大多数情况下会,在数据分布不均衡的情况下,还是别用绑定变量了,从上面的例子可以看出,使用了绑定变量,如果表记录达到百万级别,然后通过索引扫描,那将会对性能带来多大影响!,然而这个时候不使用绑定变量,只有三种情况 select owner from test where status='VALID',select owner from test where status='INVALID',select owner from test where status='UNKONWN',并不会给shared pool带来多大的问题,因为status值只有3个,重复解析最多3次。

2不要轻易相信autotrace(大多数情况下还是准确的)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值