Oracle 表的访问方式(2)-----索引扫描
索引扫描(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)-----索引扫描的更多相关文章
- Oracle 表的访问方式(1) ---全表扫描、通过ROWID访问表
1.Oracle访问表的方式 全表扫描.通过ROWID访问表.索引扫描 2.全表扫描(Full Table Scans, FTS) 为实现全表扫描,Oracle顺序地访问表中每条记录,并检查每一条记录 ...
- oracle 表空管理方式(LMT)、ASSM段管理方式、一级位图块、二级位图块、三级位图块。
今天是2013-12-16,今天和明天是我学习oracle生涯中一个特殊的日子.今天晚上进行了一下表空间管理方式的学习,在此记录一下笔记. 对于oracle数据库最小i/0单位是数据块,最想分配空间单 ...
- Oracle 表的连接方式(2)-----HASH JOIN的基本机制1
我们对hash join的常见误解,一般包括两个: 第一个误解:是我们经常以为hash join需要对两个做join的表都做全表扫描 第二个误解:是经常以为hash join会选择比较小的表做buil ...
- Oracle 表的连接方式(2)-----HASH JOIN的基本机制2
Hash算法原理 对于什么是Hash算法原理?这个问题有点难度,不是很好说清楚,来做一个比喻吧:我们有很多的小猪,每个的体重都不一样,假设体重分布比较平均(我们考虑到公斤级别),我们按照体重来分,划分 ...
- Oracle 表的连接方式(2)-----HASH JOIN的基本机制3
HASH JOIN的模式 hash join有三种工作模式,分别是optimal模式,onepass模式和multipass模式,分别在v$sysstat里面有对应的统计信息: SQL> sel ...
- Oracle 表的连接方式(1)-----Nested loop join和 Sort merge join
关系数据库技术的精髓就是通过关系表进行规范化的数据存储,并通过各种表连接技术和各种类型的索引技术来进行信息的检索和处理. 表的三种关联方式: nested loop:从A表抽一条记录,遍历B表查找匹配 ...
- ORACLE表空间管理方式segment和extent
A permanent tablespace contains persistent schema objects. Objects in permanent tablespaces are stor ...
- Oracle 表的连接方式
1. 连接说明 ① Oracle一次只能连接两个表.不管查询中有多少个表,Oracle 在连接中一次仅能操作两张表. ② 当执行多个表的连接时,优化器从一个表开始,将它与另一个表连接:然后将中间结果与 ...
- Oracle EM 的访问方式由HTTPS改为HTTP
打开命令提示符,依次运行以下命令: set ORACLE_HOSTNAME=%COMPUTERNAME% set ORACLE_UNQNAME=orcl rem 指向 dbhome_1\oc4j\j2 ...
随机推荐
- 基于 Equinox 的 OSGi Console 的研究和探索
自定制 OSGi Console 进行组建和服务生命周期管理模块化编程的好处已经很好地被理解了约 40 年,但在 OSGi 之前,开发人员不得不自己发明模块化设计和系统.随着软件应用体系结构的不断发展 ...
- 关于Google Chorme中字体小于12px的问题
问题:当字体大小设置成小于12px时,Google chrome中字体的大小始终显示为12px. 而其他浏览器则没有这个问题. 这时只需要在要改变字体大小的元素中添加 -webkit-transfor ...
- Linq中使用Left Join
use Test Create table Student( ID ,) primary key, ) not null ) Create Table Book( ID ,) primary key, ...
- CALayer 简单操作和实际应用
1.CALayer //每一个UIView,都存在一个CALayer.(主层) //CALayer的功能 描边,圆角,阴影... //CALayer 属于QuartzCore绘图框架 //明明有UIC ...
- 我关于SecureCRT远程连接失败的问题解决办法
使用VirtualBox搭建一个ubuntu14.04的系统环境,为了省去主机与虚拟机直接互相直接一直切换的频繁操作,所以想到了使用SecureCRT连接,但是出现了连接问题,问题如下图:
- 如何用ASP.NET实现bosh模拟http双向长连接请求
在做研究之前先简单说一下之前公司的通讯模块.最早的时候公司开发的web管理系统是需要配合c++桌面客户端进行一些系统底层操作,并非普通的b/s架构,或者c/s架构,因为需求是可以通过web管理系统向客 ...
- Cocos2d-JS中瓦片地图API
为了访问瓦片地图,Cocos2d-JS中访问瓦片地图API,主要的类有:TMXTiledMap.TMXLayer和TMXObjectGroup等.1.TMXTiledMapTMXTiledMap是瓦片 ...
- Cocos2d-JS内置粒子系统
从类图中我们可以看到,Cocos2d-JS中有内置的11种粒子,这些粒子的属性都是预先定义好的,我们也可以在程序代码中单独修改某些属性,我们在上一节的实例中都已经实现了这些属性的设置.内置粒子系统内置 ...
- ios开发:Core Data概述
Core Data 概述 2005年的四月份,Apple 发布了 OS X 10.4,在这个版本中 Core Data 框架发布了.Core Data本身既不是数据库也不是数据库访问框架.相反,Cor ...
- HDU1106 排序
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1106 Problem Description 输入一行数字,如果我们把这行数字中的‘5’都看成空格 ...