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 ...
随机推荐
- 【阿里云产品公测】结构化数据服务OTS之JavaSDK初体验
[阿里云产品公测]结构化数据服务OTS之JavaSDK初体验 作者:阿里云用户蓝色之鹰 一.OTS简单介绍 OTS 是构建在阿里云飞天分布式系统之上的NoSQL数据库服务,提供海量结构化数据的存储和实 ...
- NSDate简单介绍
NSDate简单介绍 一:NSDate是一个日期\时间方面的类,主要用来创建\获取时间 1.NSDate对象的创建: date 创建一个当前系统日期和时间的对象 dateWithTimeInterva ...
- python 基础——多重继承
原始的初始化 子类直接调用超类 __init__ 方法初始化,当形成钻石继承的时候,超类会被多次初始化,可能会有意向不到的问题: BaseClass / \ OneClass Tw ...
- UIScrollView的相关属性说明
_scrollView = [[UIScrollView alloc] init]; //height = 0:禁止垂直方向滚动 _scrollView.contentSize = CGSizeMak ...
- hdu1251
统计难题 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)Total Submi ...
- Python之类型转换
函数 描述 int(x [,base]) 将x转换为一个整数 long(x [,base] ) 将x转换为一个长整数 float(x) 将x转换到一个浮点数 complex(real [,imag]) ...
- JavaScript:exec()方法的用法及说明
最近在看某知名js框架的源码,突然间发现自己对exec()方法竟然不太理解,然后就仔细的分析了一下这个方法 下面贴个exec()方法使用的代码出来 rquickExpr = /^(?:\s*(< ...
- dispatch_async 子线程,主线程的简单用法
子线程的使用方法: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{ //子线程的处理逻辑 ...
- 正确使用Android性能分析工具——TraceView
http://blog.jobbole.com/78995/ 首页 最新文章 IT 职场 前端 后端 移动端 数据库 运维 其他技术 - 导航条 - 首页 最新文章 IT 职场 前端 - Ja ...
- DOS 批处理 修改xml文件
之前对批处理和dos只停留在cd ping ipconfig水平,我以为改个文件应该很简单吧,把文件读出来做个替换再写回去不就欧了,百度个例子改改,那还不是分分钟的事,哪知道事实比想的要复杂的多. 我 ...