[20180316]为什么不使用INDEX FULL SCAN (MIN/MAX).txt

--//链接:http://www.itpub.net/thread-2100456-1-1.html.自己重复测试看看.

1.环境:

SCOTT@book> @ &r/ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

SCOTT@book> create table t as select * from dba_objects ;
Table created.

SCOTT@book> create index i_t_object_id on t(object_id);
Index created.

--//分析表略.Method_Opt => 'FOR ALL COLUMNS SIZE 1 '.

2.测试:
SCOTT@book> select /*+ index(t,i_t_object_id) */ nvl2(max(object_id),max(object_id),3000000)+1 n10 from t;
                  N10
---------------------
                90461

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  f2u3nkrcsdzbb, child number 0
-------------------------------------
select /*+ index(t,i_t_object_id) */
nvl2(max(object_id),max(object_id),3000000)+1 n10 from t
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id  | Operation          | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |        |       |   347 (100)|          |
|   1 |  SORT AGGREGATE    |      |      1 |     5 |            |          |
|   2 |   TABLE ACCESS FULL| T    |  86989 |   424K|   347   (1)| 00:00:05 |
----------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   2 - SEL$1 / T@SEL$1

--//连索引都不用.设置约束object_id is null 看看.

SCOTT@book> delete from t where object_id is null ;
2 rows deleted.

SCOTT@book> commit ;
Commit complete.

SCOTT@book> alter table t modify(object_id  not null);
Table altered.

SCOTT@book> select /*+ index(t,i_t_object_id) */ nvl2(max(object_id),max(object_id),3000000)+1 n10 from t;
                  N10
---------------------
                90461

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  f2u3nkrcsdzbb, child number 0
-------------------------------------
select /*+ index(t,i_t_object_id) */
nvl2(max(object_id),max(object_id),3000000)+1 n10 from t
Plan hash value: 4145094723
----------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |        |       |   195 (100)|          |
|   1 |  SORT AGGREGATE             |               |      1 |     5 |            |          |
|   2 |   FIRST ROW                 |               |  86989 |   424K|   195   (1)| 00:00:03 |
|   3 |    INDEX FULL SCAN (MIN/MAX)| I_T_OBJECT_ID |  86989 |   424K|   195   (1)| 00:00:03 |
----------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   3 - SEL$1 / T@SEL$1
Note
-----
   - Warning: basic plan statistics not available. These are only collected when:
       * hint 'gather_plan_statistics' is used for the statement or
       * parameter 'statistics_level' is set to 'ALL', at session or system level

--//可以使用索引,并且走INDEX FULL SCAN (MIN/MAX).不加提示看看:

SCOTT@book> select /*+ inde111x(t,i_t_object_id) */ nvl2(max(object_id),max(object_id),3000000)+1 n10 from t;
                  N10
---------------------
                90461

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  1d6mkncu6tjms, child number 0
-------------------------------------
select /*+ inde111x(t,i_t_object_id) */
nvl2(max(object_id),max(object_id),3000000)+1 n10 from t
Plan hash value: 3095383276
----------------------------------------------------------------------------------------
| Id  | Operation             | Name          | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |               |        |       |    54 (100)|          |
|   1 |  SORT AGGREGATE       |               |      1 |     5 |            |          |
|   2 |   INDEX FAST FULL SCAN| I_T_OBJECT_ID |  86989 |   424K|    54   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   2 - SEL$1 / T@SEL$1
Note
-----
   - Warning: basic plan statistics not available. These are only collected when:
       * hint 'gather_plan_statistics' is used for the statement or
       * parameter 'statistics_level' is set to 'ALL', at session or system level

--//可以发现不加提示,虽然使用索引,但是执行计划走的是INDEX FAST FULL SCAN.
--//注意看一个细节:cost=54.而前面加提示:cost=195,为什么会这样,导致执行计划认为选择INDEX FAST FULL SCAN更优.

SCOTT@book> alter session set statistics_level=all;

Session altered.

SCOTT@book> select  max(object_id) n10 from t;
                  N10
---------------------
                90460

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  df1726cj0y4vz, child number 0
-------------------------------------
select  max(object_id) n10 from t
Plan hash value: 2939893782
--------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name          | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |               |      1 |        |       |     2 (100)|          |      1 |00:00:00.01 |       2 |
|   1 |  SORT AGGREGATE            |               |      1 |      1 |     5 |            |          |      1 |00:00:00.01 |       2 |
|   2 |   INDEX FULL SCAN (MIN/MAX)| I_T_OBJECT_ID |      1 |      1 |     5 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |
--------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   2 - SEL$1 / T@SEL$1

--//如果取最大值cost=2.问题集中在select /*+ index(t,i_t_object_id) */ nvl2(max(object_id),max(object_id),3000000)+1 n10 from t;的cost如何计算.

--//oraclenvl2,nvl函数有一个特点,要先运算第2,3个参数值.如下例子可以证明:

SYS@book> grant execute on sys.dbms_lock to scott;
Grant succeeded.

--//以scott用户执行:
CREATE OR REPLACE FUNCTION SCOTT.sleep (seconds IN NUMBER)
RETURN NUMBER AS
BEGIN
  sys.dbms_lock.sleep(seconds);
  RETURN seconds;
END;
/

SCOTT@book> set timing on
SCOTT@book> select nvl2(1,sleep(1),sleep(2)) from dual ;
NVL2(1,SLEEP(1),SLEEP(2))
-------------------------
                        1
Elapsed: 00:00:03.00
--//执行需要时间3秒.也就证明先运算sleep(1),sleep(2),在算第1个参数,oracle不会选择短路执行路径.

SCOTT@book> select /*+ index(t,i_t_object_id) */ nvl2(max(object_id),max(object_id),3000000)+1 n10 from t;
                  N10
---------------------
                90461

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  f2u3nkrcsdzbb, child number 0
-------------------------------------
select /*+ index(t,i_t_object_id) */
nvl2(max(object_id),max(object_id),3000000)+1 n10 from t
Plan hash value: 4145094723
---------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |      1 |        |       |   195 (100)|          |      1 |00:00:00.01 |       2 |
|   1 |  SORT AGGREGATE             |               |      1 |      1 |     5 |            |          |      1 |00:00:00.01 |       2 |
|   2 |   FIRST ROW                 |               |      1 |  86989 |   424K|   195   (1)| 00:00:03 |      1 |00:00:00.01 |       2 |
|   3 |    INDEX FULL SCAN (MIN/MAX)| I_T_OBJECT_ID |      1 |  86989 |   424K|   195   (1)| 00:00:03 |      1 |00:00:00.01 |       2 |
---------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   3 - SEL$1 / T@SEL$1

--//注意看E-Rows=86989.而前面select  max(object_id) n10 from t;的E-Rows=1.可以认为当执行nvl2(max(object_id),max(object_id),3000000)+1时,
--//第2个参数max(object_id),oracle认为这个是变量,运算86989次.导致成本上升为195,通过10053定位看看.
--//而如果使用nvl函数nvl(max(object_id),3000000)+1,第2参数是常量,不需要这种的运算.

3.10053分析:

SCOTT@book> @ &r/10053on 12
Session altered.

SCOTT@book> Select /*+ index(t,i_t_object_id) */ nvl2(max(object_id),max(object_id),3000000)+1 n10 from t;
                  N10
---------------------
                90461

--//注意要改动sql语句,进行1次硬分析10053才跟踪到.

SCOTT@book> @ &r/10053off
Session altered.

--//检查转储:
-----------------------------
SYSTEM STATISTICS INFORMATION
-----------------------------
  Using NOWORKLOAD Stats
  CPUSPEEDNW: 3074 millions instructions/sec (default is 100)
  IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
  IOSEEKTIM:  10 milliseconds (default is 10)
  MBRC:       NO VALUE blocks (default is 8)

***************************************
BASE STATISTICAL INFORMATION
***********************
Table Stats::
  Table:  T  Alias:  T
    #Rows: 86989  #Blks:  1270  AvgRowLen:  98.00  ChainCnt:  0.00
Index Stats::
  Index: I_T_OBJECT_ID  Col#: 4
    LVLS: 1  #LB: 193  #DK: 86987  LB/K: 1.00  DB/K: 1.00  CLUF: 1368.00
    User hint to use this index
Access path analysis for T
***************************************
SINGLE TABLE ACCESS PATH
  Single Table Cardinality Estimation for T[T]
  Table: T  Alias: T
    Card: Original: 86989.000000  Rounded: 86989  Computed: 86989.00  Non Adjusted: 86989.00
  Access Path: index (FullScan)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    Index: I_T_OBJECT_ID
    resc_io: 194.00  resc_cpu: 18778959
    ix_sel: 1.000000  ix_sel_with_filters: 1.000000
    Cost: 194.51  Resp: 194.51  Degree: 1
  Best:: AccessPath: IndexRange
  Index: I_T_OBJECT_ID
         Cost: 194.51  Degree: 1  Resp: 194.51  Card: 86989.00  Bytes: 0
***************************************
--//注意看下划线部分  Access Path: index (FullScan).
--//  Best:: AccessPath: IndexRange

--//对比如下的10053转储
SCOTT@book> @ &r/10053on 12
Session altered.

SCOTT@book> Select  max(object_id) n10 from t;
                  N10
---------------------
                90460

SCOTT@book> @ &r/10053off
Session altered.

BASE STATISTICAL INFORMATION
***********************
Table Stats::
  Table:  T  Alias:  T
    #Rows: 86989  #Blks:  1270  AvgRowLen:  98.00  ChainCnt:  0.00
Index Stats::
  Index: I_T_OBJECT_ID  Col#: 4
    LVLS: 1  #LB: 193  #DK: 86987  LB/K: 1.00  DB/K: 1.00  CLUF: 1368.00
Access path analysis for T
***************************************
SINGLE TABLE ACCESS PATH
  Single Table Cardinality Estimation for T[T]
  Table: T  Alias: T
    Card: Original: 86989.000000  Rounded: 86989  Computed: 86989.00  Non Adjusted: 86989.00
  Access Path: TableScan
    Cost:  346.74  Resp: 346.74  Degree: 0
      Cost_io: 346.00  Cost_cpu: 27311919
      Resp_io: 346.00  Resp_cpu: 27311919
  Access Path: index (index (FFS))
    Index: I_T_OBJECT_ID
    resc_io: 54.00  resc_cpu: 11812878
    ix_sel: 0.000000  ix_sel_with_filters: 1.000000
  Access Path: index (FFS)
    Cost:  54.32  Resp: 54.32  Degree: 1
      Cost_io: 54.00  Cost_cpu: 11812878
      Resp_io: 54.00  Resp_cpu: 11812878
  Access Path: index (Min/Max)
    Index: I_T_OBJECT_ID
    resc_io: 2.00  resc_cpu: 14443
    ix_sel: 0.000000  ix_sel_with_filters: 0.000000
    Cost: 2.00  Resp: 2.00  Degree: 1
  Best:: AccessPath: IndexRange
  Index: I_T_OBJECT_ID
         Cost: 2.00  Degree: 1  Resp: 2.00  Card: 1.00  Bytes: 0
***************************************

--//可以看出oracle分析得到的最佳执行计划实际上是Best:: AccessPath: IndexRange.
--//cost的成本实际上是IndexRange的成本.

SCOTT@book> select /*+ index(t) */ count(*) from t where object_id between 1 and 1e6;
  COUNT(*)
----------
     86987

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  1ypsa9k66p3us, child number 0
-------------------------------------
select /*+ index(t) */ count(*) from t where object_id between 1 and 1e6
Plan hash value: 565091764
-----------------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name          | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |               |      1 |        |       |   195 (100)|          |      1 |00:00:00.03 |     194 |
|   1 |  SORT AGGREGATE   |               |      1 |      1 |     5 |            |          |      1 |00:00:00.03 |     194 |
|*  2 |   INDEX RANGE SCAN| I_T_OBJECT_ID |      1 |  86987 |   424K|   195   (1)| 00:00:03 |  86987 |00:00:00.02 |     194 |
-----------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   2 - SEL$1 / T@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("OBJECT_ID">=1 AND "OBJECT_ID"<=1000000)

--//注:一定要加提示/*+ index(t) */,不然执行计划会选择INDEX FAST FULL SCAN.而这样执行计划是INDEX RANGE SCAN.cost正好是195.
--//这样的结果导致执行计划不会选择INDEX FULL SCAN (MIN/MAX).

--//实际上可以使用Coalesce参数可以避免短路执行.
SCOTT@book> select Coalesce(1,sleep(1)) from dual ;
COALESCE(1,SLEEP(1))
--------------------
                   1

SCOTT@book> set timing on
SCOTT@book> select Coalesce(1,sleep(1)) from dual ;
COALESCE(1,SLEEP(1))
--------------------
                   1

Elapsed: 00:00:00.01
SCOTT@book> set timing off
--//Coalesce参数可以短路执行.

SCOTT@book> Select /*+ ind111ex(t,i_t_object_id) */ Coalesce(max(object_id),3000000)+1 n10 from t;
                  N10
---------------------
                90461

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
--------------------------------------
SQL_ID  7m1705d3c8b1c, child number 0
-------------------------------------
Select /*+ ind111ex(t,i_t_object_id) */
Coalesce(max(object_id),3000000)+1 n10 from t

Plan hash value: 2939893782

--------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name          | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |               |      1 |        |       |     2 (100)|          |      1 |00:00:00.01 |       2 |
|   1 |  SORT AGGREGATE            |               |      1 |      1 |     5 |            |          |      1 |00:00:00.01 |       2 |
|   2 |   INDEX FULL SCAN (MIN/MAX)| I_T_OBJECT_ID |      1 |      1 |     5 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |
--------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   2 - SEL$1 / T@SEL$1

--//最主要问题在于开发根本不应该使用nvl2函数.nvl,Coalesce就没有问题.

[20180316]为什么不使用INDEX FULL SCAN (MIN/MAX).txt的更多相关文章

  1. Oracle 11G INDEX FULL SCAN 和 INDEX FAST FULL SCAN 对比分析

    SQL> drop table test; 表已删除. SQL> create table test as select * from dba_objects where 1!=1; 表已 ...

  2. 【每日一摩斯】-Index Skip Scan Feature (212391.1)

    INDEX Skip Scan,也就是索引快速扫描,一般是指谓词中不带复合索引第一列,但扫描索引块要快于扫描表的数据块,此时CBO会选择INDEX SS的方式. 官方讲的,这个概念也好理解,如果将复合 ...

  3. INDEX FAST FULL SCAN和INDEX FULL SCAN

    INDEX FULL SCAN 索引全扫描.单块读 .它扫描的结果是有序的,因为索引是有序的.它通常发生在 下面几种情况(注意:即使SQL满足以下情况 不一定会走索引全扫描) 1. SQL语句有ord ...

  4. Index Full Scan vs Index Fast Full Scan-1103

    [Oracle] Index Full Scan vs Index Fast Full Scan作者:汪海 (Wanghai) 日期:14-Aug-2005 出处:http://spaces.msn. ...

  5. index full scan/index fast full scan/index range scan

    **************************1************************************* 索引状态:          valid.      N/A .    ...

  6. index unique scan

    INDEX UNIQUE SCAN 索引唯一扫描.单块读 只可能发生在unique index/primary key 等值查找                      等待事件:db file s ...

  7. INDEX RANG SCAN无需回表的情况

    create table a3 as select * from dba_objects create index a3_idx1 on a3(owner); select owner from a3 ...

  8. 索引跳跃式扫描(INDEX SKIP SCAN)

    索引跳跃式扫描(INDEX SKIP SCAN) 索引跳跃式扫描(INDEX SKIP SCAN)适用于所有类型的复合B树索引(包括唯一性索引和非唯一性索引),它使那些在where条件中没有对目标索引 ...

  9. 索引全扫描(INDEX FULL SCAN)

    所谓的索引全扫描(INDEX FULL SCAN)就是指要扫描目标索引所有叶子块的所有索引行.这里需要注意的是,索引全扫描需要扫描目标索引的所有叶子块,但这并不意味着需要扫描该索引的所有分支块.在默认 ...

随机推荐

  1. mongodb远程备份

    创建备份用户 db.createUser({user: 'backup',pwd: 'back123' ,roles : [{role : 'userAdminAnyDatabase' ,db : ' ...

  2. Koa 框架教程

    Koa 框架教程   作者: 阮一峰 日期: 2017年8月 9日 Node 主要用在开发 Web 应用.这决定了使用 Node,往往离不开 Web 应用框架. Koa 就是一种简单好用的 Web 框 ...

  3. 课程四(Convolutional Neural Networks),第四 周(Special applications: Face recognition & Neural style transfer) —— 3.Programming assignments:Face Recognition for the Happy House

    Face Recognition for the Happy House Welcome to the first assignment of week 4! Here you will build ...

  4. Xshell连接ESXI方法

    第一步.ESXI打开ssh功能按住F2进入设置如下图: 第二步.输入密码 第三步.选择Troubleshooting Options 回车 第四步.选择Enable SSH 这里只介绍了一种方式打开E ...

  5. 离不开的微服务架构,脱不开的RPC细节

    服务化有什么好处? 服务化的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现大公司跨团队的技术解耦,如下图所示: 服务A:欧洲团队维护,技术背景是Java 服务B:美洲团队维护,用C++实现 ...

  6. js实现oss文件上传及一些问题

    关于兼容性问题,ie8以下的可以使用4.x的版本 一.引入sdk和jq <script src="http://libs.baidu.com/jquery/2.0.0/jquery.m ...

  7. 从零开始学 Web 之 Ajax(三)Ajax 概述,快速上手

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  8. Java并发编程之volatile关键字

    大概是因为项目.业务的原因,工作上几乎还没有使用过多线程相关的功能,相关知识差不多都忘了,所以最近补一下基础. volatile用来修饰共享变量,volatile变量具有 synchronized 的 ...

  9. Python机器学习笔记:深入学习Keras中Sequential模型及方法

    Sequential 序贯模型 序贯模型是函数式模型的简略版,为最简单的线性.从头到尾的结构顺序,不分叉,是多个网络层的线性堆叠. Keras实现了很多层,包括core核心层,Convolution卷 ...

  10. .Net Core缓存组件(Redis)源码解析

    上一篇文章已经介绍了MemoryCache,MemoryCache存储的数据类型是Object,也说了Redis支持五中数据类型的存储,但是微软的Redis缓存组件只实现了Hash类型的存储.在分析源 ...