根据Oracle-L邮件列表里主题「

Full scan vs index

」的讨论而来。
1、测试环境创建
SYS@HEMESRHTDB2(1.206)> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE11.2.0.3.0Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
 
SYS@HEMESRHTDB2(1.206)> 
create table t2
    as
    with generator as (
     select --+ materialize
       rownum pk
       from all_objects
       where rownum<=4000
       )
    select
       /*+ ordered use_nl(v2)*/
     rownum pk,
     round(dbms_random.value(1,2)) a,
     round(dbms_random.value(1,5)) b,
     round(dbms_random.value(1,10)) c,
     round(dbms_random.value(1,100)) d,
     round(dbms_random.value(1,1000000)) e 
   from
     generator v1,
     generator v2
   where
     rownum<=600000
     /
Table created.
 
SYS@HEMESRHTDB2(1.206)> select * from t2 where rownum<=100;
 
PK    A       B  C     DE
---------- ---------- ---------- ---------- ---------- ----------
1    2       1  3    80   296354
2    2       3  9    47   531531
3    2       3  1    10   330623
4    2       5  2    35    21138
5    2       5  7    50   425066
6    2       3  9    75   322065
7    2       4  1    93    55360
8    2       1  8    99   378844
9    2       5  8    72   869863
10    2       5  2    63   373369
11    1       4  4    37   313221
12    1       5  8    68    40918
13    1       2  8    48   457786
14    2       3  2    83   316507
15    1       4  2    14   734118
16    1       4  7    59    47266
……
……
 
SYS@HEMESRHTDB2(1.206)> create index ix_t2_key on t2(PK,A) online nologging;
Index created.
SYS@HEMESRHTDB2(1.206)> create index ix_t2_D on t2(D) online nologging;
Index created.
SYS@HEMESRHTDB2(1.206)> alter session set statistics_level ='ALL' ; 
Session altered.
 
2、测试4种情况
索引情况。
ix_t2_key on t2(PK,A) 
ix_t2_D   on t2(D)
 
Select count(*) from T2 where pk > 520000;
select count(*) from t2 where A=1;
Select count(D) from T2 where pk > 520000;
3、测试
实验1
SYS@HEMESRHTDB2(1.206)> select count(*) from T2 where pk > 520000;
SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
 
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID9c98xbdbfww9r, child number 0
-------------------------------------
Select count(*) from T2 where pk > 520000
 
Plan hash value: 2050414396
 
 
实验2
SYS@HEMESRHTDB2(1.206)> select count(*) from t2 where A=1;
 
  COUNT(*)
----------
    299737
 
SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
 
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID651cjf8pmhb51, child number 0
-------------------------------------
select count(*) from t2 where A=1
 
Plan hash value: 2933116225
实验3
SYS@HEMESRHTDB2(1.206)> select count(D) from t2 where pk>=520000; 
 
  COUNT(D)
----------
     80001
 
SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
 
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID41uuvuyutgn6q, child number 0
-------------------------------------
select count(D) from t2 where pk>=520000
 
Plan hash value: 3321871023
4、结论和延伸
实验1
SYS@HEMESRHTDB2(1.206)> select count(*) from T2 where pk > 520000;
按照预期走索引IX_T2_KEY。
实验2
SYS@HEMESRHTDB2(1.206)> select count(*) from t2 where A=1;
也同预期。
实验3
SYS@HEMESRHTDB2(1.206)> select count(D) from t2 where pk>=520000; 
为啥变成count(D)就完全不一样了?
 
我们加上index hint看看效果如何?
 
延伸实验 Index hint
SYS@HEMESRHTDB2(1.206)> select /*+ index(T2 IX_T2_KEY) */ count(D) from t2 where pk>=520000; 
 
  COUNT(D)
----------
     80001
 
SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
 
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID4s4zzmrzdzrbt, child number 0
-------------------------------------
select /*+ index(T2 IX_T2_KEY) */ count(D) from t2 where pk>=520000
 
Plan hash value: 948933721
 
 
这儿看起来好像有些眉目了,Cost虽然比全表扫描的要大,但真正耗用的buffers根本就不大。
问题出在统计信息!!?
 
SYS@HEMESRHTDB2(1.206)> 
 
select
  column_name,
  num_distinct,
  histogram, num_buckets,
  to_char(LAST_ANALYZED, 'yyyy-mm-dd hh24:mi:ss') 
from all_tab_col_statistics 
  where upper(table_name)='T2';
 
no rows selected
 
果然咧,这时收集下统计信息。
 
SYS@HEMESRHTDB2(1.206)> 
begin
  dbms_stats.gather_table_stats(
  ownname => user,
  tabname => 'T2',
  estimate_percent =>100,
  cascade => true);
end;
/
PL/SQL procedure successfully completed.
 
「for all columns 」或者 「for all indexed columns」都OK,重要的是覆盖count(D) 字段,CBO才能够计算出正确的cost。
可以加个/*1*/之类的使执行计划重新解析,或是alter system flush shared_pool; 
嗯,随你喜欢。
 
SYS@HEMESRHTDB2(1.206)> select /*1*/ count(D) from t2 where pk>=520000;
SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID6z1bc6xv0anrn, child number 0
-------------------------------------
select /*1*/ count(D) from t2 where pk>=520000
 
Plan hash value: 948933721
 
这个时候,便会选择正确的索引了,
当然,你也可以把D字段包含入索引IX_T2_KEY中。
 
最后:
 
如果扫描的范围再一些?会发生什么?
10万/60万
 
SYS@HEMESRHTDB2(1.206)> select /*2*/ count(D) from t2 where pk>=500000; 
 
  COUNT(D)
----------
    100001
 
SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
 
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID7shudyqdb5nbk, child number 0
-------------------------------------
select /*2*/ count(D) from t2 where pk>=500000
 
Plan hash value: 3321871023
 
 

Full scan vs index 执行计划的实验的更多相关文章

  1. Oracle中的执行计划

    使用autotrace sqlplus系统参数:SQL> set autotrace trace onSQL> select * from dual;DUM---XExecution Pl ...

  2. SQL Server 性能调优 之执行计划(Execution Plan)调优

    SQL Server 存在三种 Join 策略:Hash Join,Merge Join,Nested Loop Join. Hash Join:用来处理没有排过序/没有索引的数据,它在内存中把 Jo ...

  3. PostgreSQL执行计划:Bitmap scan VS index only scan

    之前了解过postgresql的Bitmap scan,只是粗略地了解到是通过标记数据页面来实现数据检索的,执行计划中的的Bitmap scan一些细节并不十分清楚.这里借助一个执行计划来分析bitm ...

  4. MySQL 执行计划中Extra(Using where,Using index,Using index condition,Using index,Using where)的浅析

      关于如何理解MySQL执行计划中Extra列的Using where.Using Index.Using index condition,Using index,Using where这四者的区别 ...

  5. 执行计划中常见index访问方式(转)

    近期有朋友对于单个表上的index各种情况比较模糊,这里对于单个表上,单个index出现的大多数情况进行了总结性测试,给出了测试结果,至于为什么出现这样的试验结果未做过多解释,给读者留下思考的空间.本 ...

  6. MySQL执行计划extra中的using index 和 using where using index 的区别

    本文出处:http://www.cnblogs.com/wy123/p/7366486.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...

  7. 索引使用,分析初探。(explain分析执行计划,以及强制使用force index)

    促使这次探索的初衷还是因为要对一个定时脚本性能进行优化. 脚本有两个指定状态分别是status, latest_process_status,和一个超期时间expire_time进行限制. 按照我以前 ...

  8. [z]Oracle性能优化-读懂执行计划

    http://blog.csdn.net/lifetragedy/article/details/51320192 Oracle的执行计划   得到执行计划的方式       Autotrace例子 ...

  9. Oracle 课程五之优化器和执行计划

    课程目标 完成本课程的学习后,您应该能够: •优化器的作用 •优化器的类型 •优化器的优化步骤 •扫描的基本类型 •表连接的执行计划 •其他运算方式的执行计划 •如何看执行计划顺序 •如何获取执行计划 ...

随机推荐

  1. linux系统编程之(一) 信号量

    信号量 一.什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明 它被占用,测 ...

  2. git撤销commit,但未git push的命令

    在git push的时候,有时候我们会想办法撤销git commit的内容 1.找到之前提交的git commit的id git log 找到想要撤销的id 2.git reset –hard id ...

  3. 网络编程api bind函数细节 select 细节

    struct sockaddr_in bindaddr; bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = htonl(INADDR_ ...

  4. php之mongodb插入数据后如何返回当前插入记录ID

    <?php /** *插入记录 *参数: *$table_name:表名 *$record:记录 * *返回值: *成功:true *失败:false */ function insert($t ...

  5. JS 用正则表达式,验证密码包含数字和字母的方法

    必须包含至少一位数字和一位字母,脚本方法如下: function CheckPassWord(password) {//密码必须包含数字和字母 var str = password; if (str ...

  6. Shader学习笔记

    Shader学习笔记 例子: Shader "SrfShader1"{ //定义显示在Inspector中的变量,并从Inspector中获取值 Properties{ _Colo ...

  7. hadoop 天气案例

    对下面一组气温数据进行处理,得到每个月份最高的两个气温值 2018-12-12 14:30 25c2018-12-12 15:30 26c2017-12-12 12:30 36c2019-01-01 ...

  8. LintCode刷题小记491

    题目: 判断一个正整数是不是回文数. 回文数的定义是,将这个数反转之后,得到的数仍然是同一个数. 样例: 11, 121, 1, 12321 这些是回文数. 23, 32, 1232 这些不是回文数. ...

  9. solidity合约面向对象

    1. 属性[状态变量]的访问权限 public  internal[合约属性默认的权限]  private 说明:属性默认访问全向为internal,internal和private类型的属性,外部是 ...

  10. javascript获取后台传来的json

    Mvc Razor视图引擎中 <script type="text/javascript"> var _temp = @(new MvcHtmlString(this. ...