索引扫描(Index scan)

  我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值),然后根据rowid直接从表中得到具体的数据,这种查找方式称为索引扫描或索引查找(index lookup)。一个rowid唯一的表示一行数据,该行对应的数据块是通过一次i/o得到的,在此情况下该次i/o只会读取一个数据库块。在索引中,除了存储每个索引的值外,索引还存储具有此值的行对应的ROWID值。索引扫描可以由2步组成: (1) 扫描索引得到对应的rowid值。 (2) 通过找到的rowid从表中读出具体的数据。

根据索引的类型与where限制条件的不同,有5种类型的索引扫描:

1)索引唯一扫描(index unique scan)

2)索引范围扫描(index range scan)

3)索引全扫描(index full scan)

4)索引快速扫描(index fast full scan)

5)索引跳跃扫描(INDEX SKIP SCAN)

索引唯一扫描(INDEX UNIQUE SCAN)

  通过唯一索引查找一个数值经常返回单个ROWID

唯一索引由单独列组成:

 --收集统计信息
SQL> exec dbms_stats.gather_table_stats('SCOTT','EMP'); PL/SQL procedure successfully completed. Commit complete.
SQL> --获取创建索引语句
SQL> SELECT DBMS_METADATA.GET_DDL('INDEX',u.index_name)
2 FROM USER_INDEXES u
3 WHERE u.TABLE_NAME='EMP'; DBMS_METADATA.GET_DDL('INDEX',U.INDEX_NAME)
--------------------------------------------------------------------------------
CREATE UNIQUE INDEX "SCOTT"."PK_EMP" ON "SCOTT"."EMP" ("EMPNO")
PCTFREE 10 SQL> 1.索引名称 PK_EMP
2.索引包含列 EMPNO
3.索引为唯一索引 --执行计划走唯一索引的语句
SQL> SELECT * FROM SCOTT.EMP WHERE EMPNO=''; Execution Plan
----------------------------------------------------------
Plan hash value: 2949544139 --------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
-------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("EMPNO"=7369) SQL> SELECT * FROM SCOTT.EMP WHERE EMPNO IN ('',''); Execution Plan
----------------------------------------------------------
Plan hash value: 2355049923 ---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 76 | 2 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 2 | 76 | 2 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | PK_EMP | 2 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 3 - access("EMPNO"=7499 OR "EMPNO"=7521) SQL> SELECT * FROM SCOTT.EMP WHERE EMPNO='' OR EMPNO=''; Execution Plan
----------------------------------------------------------
Plan hash value: 2355049923 ---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 76 | 2 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 2 | 76 | 2 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | PK_EMP | 2 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 3 - access("EMPNO"=7499 OR "EMPNO"=7521)
SQL>

SELECT * FROM SCOTT.EMP WHERE EMPNO='7369';
 SELECT * FROM SCOTT.EMP WHERE EMPNO IN ('7499','7521');
 SELECT * FROM SCOTT.EMP WHERE EMPNO='7499' OR EMPNO='7521'
 总结,索引在where条件中,且谓词条件可以确定唯一值时,走唯一索引。思考下2,3语句的查询过程

唯一索引由多个列组成(即组合索引)

     --创建一个唯一索引(优质索引)
create unique index scott.idx_test on scott.emp(ename, deptno); --ename为引导列,表中ename列值具有唯一性 --谓词条件中的列顺序与索引的列顺序完全一致,走唯一索引
SQL> select * from scott.emp where ename = 'ALLEN' and deptno = 20 ; no rows selected Execution Plan
----------------------------------------------------------
Plan hash value: 4010583877 ----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | IDX_TEST | 1 | | 0 (0)| 00:00:01 |
---------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("ENAME"='ALLEN' AND "DEPTNO"=20) --谓词条件中的列顺序与唯索引的列顺序不一致 ,走唯一索引
SQL> select * from scott.emp where deptno = 20 and ename = 'ALLEN'; no rows selected Execution Plan
----------------------------------------------------------
Plan hash value: 4010583877 ----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | IDX_TEST | 1 | | 0 (0)| 00:00:01 |
---------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("ENAME"='ALLEN' AND "DEPTNO"=20) --只有引导列在谓词条件中
SQL> select * from scott.emp where ename = 'ALLEN'; --即使是唯一数据 也不走唯一索引 Execution Plan
----------------------------------------------------------
Plan hash value: 2317538385 ----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_TEST | 1 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("ENAME"='ALLEN') --引导列不在谓词条件中
SQL> select * from scott.emp where deptno = 20; Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932 --------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 190 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 5 | 190 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - filter("DEPTNO"=20) SQL>
     --创建一个唯一索引(劣质索引)
create unique index idx_test on scott.emp(deptno,ename); --deptno为引导列,表中deptno列值不具有唯一性 分别对别如下sql的执行计划:
--谓词条件中的列顺序与索引的列顺序完全一致,,走唯一索引
SQL> select * from scott.emp where deptno = 20 and ename = 'ALLEN'; no rows selected Execution Plan
----------------------------------------------------------
Plan hash value: 1531058326 ------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | IDX_TEST01 | 1 | | 0 (0)| 00:00:01 |
------------------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("DEPTNO"=20 AND "ENAME"='ALLEN') SQL> --谓词条件中的列顺序与唯索引的列顺序不一致 ,走唯一索引
SQL> select * from scott.emp where ename = 'ALLEN' and deptno = 20 ; no rows selected Execution Plan
----------------------------------------------------------
Plan hash value: 1531058326 ------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | IDX_TEST01 | 1 | | 0 (0)| 00:00:01 |
------------------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("DEPTNO"=20 AND "ENAME"='ALLEN') SQL> --只有引导列在谓词条件中
SQL> select * from scott.emp where deptno = 20; Execution Plan
----------------------------------------------------------
Plan hash value: 560737562 ------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 190 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 5 | 190 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_TEST01 | 5 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("DEPTNO"=20)
SQL> --引导列不在谓词条件
SQL> select * from scott.emp where ename = 'ALLEN'; Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932 --------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 38 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - filter("ENAME"='ALLEN') SQL>

总结:使用组合索引时,遵守以下原则:

1.引导列标识性要强;

2.索引列尽量全部出现在谓词条件中

3.引导列尽量出现在谓词条件中

索引范围扫描(INDEX RANGE SCAN)

  使用一个索引存取多行数据,在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符 (如>、<、<>、>=、<=、between)。在非唯一索引上,谓词"="也可能返回多行数据,所以在非唯一索引上都使用索引范围扫描。

  使用index rang scan的3种情况:

  1.在唯一索引列上使用了range操作符(> < <> >= <= between)

  2.在组合索引上,只使用部分列进行查询,导致查询出多行

  3.对非唯一索引列上进行的任何查询。

  通过index range scan访问的表可以通过按照索引顺序重新建立表来提高效率:

1.如果你只读一部分数据,假设20% ,如果表数据顺序混乱,实际上可能把整个表都读进来了;
如果表顺序和索引一致,则只需要读进 20%的表的block就够了。这是简单情况
2.复杂情况下,顺序混乱的时候 block 可能在整个查询的不同时间点多次反复访问
当再次要访问这个块的时候说不定已经被换出去了,或者被修改过了,那代价更大
而如果顺序一样,对同一个block的访问集中在一段连续的很短的时间内,变数少,不会对同一个block产生多次IO

Index Unique Scan对比Index Range Scan

1.Index Unique Scan和Index Range Scan在B Tree上的搜索路径是一样的
2.Index Unique Scan在找到应该含有要找的Index Key的block后便停止了搜索,因为该键是唯一的;而Index Range Scan还要循着指针继续找下去直到条件不满足时
3.Index Unique Scan和Index Range Scan都只是索引上的查询,与是否扫描表没有关系。
如果所选择的列都在index上就不用去scan table;如果扫描到表, 必然还有一个table access by rowid

索引全扫描(index full scan)

  与全表扫描对应,也有相应的全索引扫描。在某些情况下,可能进行全索引扫描而不是范围扫描,需要注意的是全索引扫描只在CBO模式下才有效。 CBO根据统计数值得知进行全索引扫描比进行全表扫描更有效时,才进行全索引扫描,而且此时查询出的数据都必须从索引中可以直接得到。
 
  一般通过索引进行排序时,会用到(index full scan)

索引快速扫描(index fast full scan)

  扫描索引中的所有的数据块,与 index full scan很类似,但是一个显著的区别就是它不对查询出的数据进行排序,即数据不是以排序顺序被返回。在这种存取方法中,可以使用多块读功能,也可以使用并行读入,以便获得最大吞吐量与缩短执行时间。

索引跳跃扫描(INDEX SKIP SCAN)

  Skip Scans are initiated by probing the index for distinct values of the prefix column. Each of these distinct values is then used as a starting point for a regular index search. The result is several separate searches of a single index that, when combined, eliminate the affect of the prefix column.

  skip scan会探测出索引前导列的唯一值个数,每个唯一值都会作为常规扫描的入口,在此基础上做一次查找,最后合并 这些查询。例如:表employees (sex, employee_id, address) ,有一个组合索引(sex, employee_id). 在索引跳跃的情况 下,我们可以逻辑上把他们看成两个索引,一个是(男,employee_id),一个是(女,employee_id). select * from employees where employee_id=1;发出这个查询后,oracle先进入sex为男的入口,查找employee_id=1的条目。 再进入sex为女的入口,查找employee_id=1的条目。最后合并两个结果集

参考blog:http://www.itpub.net/thread-1372696-1-1.html

     http://blog.csdn.net/dba_waterbin/article/details/8550405

Oracle 表的访问方式(2)-----索引扫描的更多相关文章

  1. Oracle 表的访问方式(1) ---全表扫描、通过ROWID访问表

    1.Oracle访问表的方式 全表扫描.通过ROWID访问表.索引扫描 2.全表扫描(Full Table Scans, FTS) 为实现全表扫描,Oracle顺序地访问表中每条记录,并检查每一条记录 ...

  2. oracle 表空管理方式(LMT)、ASSM段管理方式、一级位图块、二级位图块、三级位图块。

    今天是2013-12-16,今天和明天是我学习oracle生涯中一个特殊的日子.今天晚上进行了一下表空间管理方式的学习,在此记录一下笔记. 对于oracle数据库最小i/0单位是数据块,最想分配空间单 ...

  3. Oracle 表的连接方式(2)-----HASH JOIN的基本机制1

    我们对hash join的常见误解,一般包括两个: 第一个误解:是我们经常以为hash join需要对两个做join的表都做全表扫描 第二个误解:是经常以为hash join会选择比较小的表做buil ...

  4. Oracle 表的连接方式(2)-----HASH JOIN的基本机制2

    Hash算法原理 对于什么是Hash算法原理?这个问题有点难度,不是很好说清楚,来做一个比喻吧:我们有很多的小猪,每个的体重都不一样,假设体重分布比较平均(我们考虑到公斤级别),我们按照体重来分,划分 ...

  5. Oracle 表的连接方式(2)-----HASH JOIN的基本机制3

    HASH JOIN的模式 hash join有三种工作模式,分别是optimal模式,onepass模式和multipass模式,分别在v$sysstat里面有对应的统计信息: SQL> sel ...

  6. Oracle 表的连接方式(1)-----Nested loop join和 Sort merge join

    关系数据库技术的精髓就是通过关系表进行规范化的数据存储,并通过各种表连接技术和各种类型的索引技术来进行信息的检索和处理. 表的三种关联方式: nested loop:从A表抽一条记录,遍历B表查找匹配 ...

  7. ORACLE表空间管理方式segment和extent

    A permanent tablespace contains persistent schema objects. Objects in permanent tablespaces are stor ...

  8. Oracle 表的连接方式

    1. 连接说明 ① Oracle一次只能连接两个表.不管查询中有多少个表,Oracle 在连接中一次仅能操作两张表. ② 当执行多个表的连接时,优化器从一个表开始,将它与另一个表连接:然后将中间结果与 ...

  9. Oracle EM 的访问方式由HTTPS改为HTTP

    打开命令提示符,依次运行以下命令: set ORACLE_HOSTNAME=%COMPUTERNAME% set ORACLE_UNQNAME=orcl rem 指向 dbhome_1\oc4j\j2 ...

随机推荐

  1. Hosts文件是什么?

    Hosts文件主要作用是定义IP地址和主机名的映射关系,是一个映射IP地址和主机名的规定.可以用文本文件打开!当用户在浏览器中输入一个需要登录的 网址时,系统会首先自动从Hosts文件中寻找对应的IP ...

  2. PHP 中mysql如何实现事务提交?

    事务就是指对数据库的多次修改,要么全部成功,要么全部失败,不能出现部分修改成功,部分修改失败的情况. PHP下操作mysql数据库要实现事务提交,需注意以下方面: 1, 数据库表存储引擎类型设置为in ...

  3. Visual Studio 2015 与GitLab 团队项目与管理【2】

    前一篇介绍了Git服务器的搭建,我采用的是CentOS7-64位系统,git版本管理使用的是GitLab,创建管理员密码后进入页面. 创建Users,需要记住Username和邮箱,初始密码可以由管理 ...

  4. HDU 1598 find the most comfortable road (MST)

    find the most comfortable road Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d ...

  5. 剑指Offer10 打印1到最大n位数

    /************************************************************************* > File Name: 10_PrintT ...

  6. 为DEDE织梦添加XMl网站地图

    在后台管理: 核心-频道模型-单页文档管理-增加一个新页面 模版文件放在你现在使用的templets目录下,sitemap.xml的内容如下 <?xml version="1.0&qu ...

  7. (转)优化js脚本设计,防止浏览器假死

    在Web开发的时候经常会遇到浏览器不响应事件进入假死状态,甚至弹出“脚本运行时间过长“的提示框,如果出现这种情况说明你的脚本已经失控了,必须进行优化. 为什么会出现这种情况呢,我们先来看一下浏览器的内 ...

  8. 说说C#和.NET的关系

    .NET和C#的关系:C#语言可以通过.NET平台编写.部署.运行.NET应用程序..NET可以支持包括C#在内的多种语言编写的应用程序..NET平台主要包括FCL(框架类库)它是微软事先定义好的类的 ...

  9. Part 14 Mathematical functions in sql server

    Part 29 Mathematical functions in sql server

  10. CSS之transition(动画)

    Transform字面上就是变形,改变的意思.在CSS中transform主要包括以下几种:旋转rotate.扭曲skew.缩放scale和移动translate以及矩阵变形matrix. 下面我们一 ...