Oracle 索引扫描的五种类型

 

之前在讨论CBORBO的时候提到了索引扫描的几种类型。

 

Oracle Optimizer CBO RBO

http://blog.csdn.net/tianlesoftware/archive/2010/08/19/5824886.aspx

 

Oracle 索引 详解

http://blog.csdn.net/tianlesoftware/archive/2010/03/05/5347098.aspx

 

Oracle Explain Plan

http://blog.csdn.net/tianlesoftware/archive/2010/08/20/5827245.aspx

 

 

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

(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。如果该唯一索引有多个列组成(即组合索引),则至少要有组合索引的引导列参与到该查询中,如创建一个索引:create index idx_test on emp(ename, deptno, loc)。则select ename from emp where ename = ‘JACK’ and deptno = ‘DEV’语句可以使用该索引。如果该语句只返回一行,则存取方法称为索引唯一扫描。而select ename from emp where deptno = ‘DEV’语句则不会使用该索引,因为where子句种没有引导列。如果存在UNIQUE PRIMARY KEY 约束(它保证了语句只存取单行)的话,Oracle经常实现唯一性扫描。

 

如:

SQL> set autot traceonly exp;   -- 只显示执行计划

SQL> select * from scott.emp t where t.empno=10;

执行计划

----------------------------------------------------------

Plan hash value: 2949544139

--------------------------------------------------------------------------------

| Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |        |     1 |    38 |     1   (0)| 00:0

|   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |     1 |    38 |     1   (0)| 00:0

|*  2 |   INDEX UNIQUE SCAN         | PK_EMP |     1 |       |     0   (0)| 00:0

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("T"."EMPNO"=10)

 

 

二.索引范围扫描(index range scan)

使用一个索引存取多行数据,同上面一样,如果索引是组合索引,而且select ename from emp where ename = ‘JACK’ and deptno = ‘DEV’语句返回多行数据,虽然该语句还是使用该组合索引进行查询,可此时的存取方法称为索引范围扫描

在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(><<>>=<=between)

 

使用索引范围扫描的例子:

 

SQL> select empno,ename from scott.emp  where empno > 7876 order by empno;

执行计划

----------------------------------------------------------

Plan hash value: 169057108

--------------------------------------------------------------------------------

| Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |        |     1 |    10 |     2   (0)| 00:0

|   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |     1 |    10 |     2   (0)| 00:0

|*  2 |   INDEX RANGE SCAN          | PK_EMP |     1 |       |     1   (0)| 00:0

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("EMPNO">7876)

 

在非唯一索引上,谓词可能返回多行数据,所以在非唯一索引上都使用索引范围扫描。

 

使用index rang scan3种情况:

(a) 在唯一索引列上使用了range操作符(> < <> >= <= between)
(b)
在组合索引上,只使用部分列进行查询,导致查询出多行。
(c)
对非唯一索引列上进行的任何查询。

 

 

三.索引全扫描(index full scan)

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

 

Oracle索引扫描的例子:

 

SQL> create index big_emp on scott.emp(empno,ename);

索引已创建。

SQL> select empno, ename from scott.emp order by empno,ename;

执行计划

----------------------------------------------------------

Plan hash value: 322359667

----------------------------------------------------------------------------

| Id  | Operation        | Name    | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------

|   0 | SELECT STATEMENT |         |    14 |   140 |     1   (0)| 00:00:01 |

|   1 |  INDEX FULL SCAN | BIG_EMP |    14 |   140 |     1   (0)| 00:00:01 |

----------------------------------------------------------------------------

 

 

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

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

 

索引快速扫描的例子:

SQL> select /*+ index_ffs(dave index_dave) */ id from dave where id>0;

执行计划

----------------------------------------------------------

Plan hash value: 674200218

--------------------------------------------------------------------------------

| Id  | Operation            | Name       | Rows  | Bytes | Cost (%CPU)| Time

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT     |            |     8 |    24 |     2   (0)| 00:00:0

|*  1 |  INDEX FAST FULL SCAN| INDEX_DAVE |     8 |    24 |     2   (0)| 00:00:0

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("ID">0)

 

为了实现这个效果,折腾了半天,最终还是用hint来了.

 

Oracle Hint

http://blog.csdn.net/tianlesoftware/archive/2010/03/05/5347098.aspx

 

 

 

. 索引跳跃扫描(INDEX SKIP SCAN

            INDEX SKIP SCAN,发生在多个列建立的复合索引上,如果SQL中谓词条件只包含索引中的部分列,并且这些列不是建立索引时的第一列时,就可能发生INDEX SKIP SCAN。这里SKIP的意思是因为查询条件没有第一列或前面几列,被忽略了。

 

Oracle 10g的文档如下:

            Index skip scans improve index scans by nonprefix columns. Often, scanning index blocks is faster than scanning table data blocks.

            Skip scanning lets a composite index be split logically into smaller subindexes. In skip scanning, the initial column of the composite index is not specified in the query. In other words, it is skipped.

            --skip scan 让组合索引(composite index)逻辑的split 成几个子索引。如果在在查询时,第一个列没有指定,就跳过它。

           

            The number of logical subindexes is determined by the number of distinct values in the initial column. Skip scanning is advantageous if there are few distinct values in the leading column of the composite index and many distinct values in the nonleading key of the index.

            -- 建议将distinct 值小的列作为组合索引的引导列,即第一列。

 

Example 13-5 Index Skip Scan

            Consider, for example, a table employees (sex, employee_id, address) with a composite index on (sex, employee_id). Splitting this composite index would result in two logical subindexes, one for M and one for F.

For this example, suppose you have the following index data:

('F',98)

('F',100)

('F',102)

('F',104)

('M',101)

('M',103)

('M',105)

 

The index is split logically into the following two subindexes:

            1The first subindex has the keys with the value F.

            2The second subindex has the keys with the value M.

 

Figure 13-2 Index Skip Scan Illustration



The column sex is skipped in the following query:

SELECT *

   FROM employees

WHERE employee_id = 101;

 

            A complete scan of the index is not performed, but the subindex with the value F is searched first, followed by a search of the subindex with the value M.

 

测试:

创建表:

SQL> create table dave_test as select owner,object_id,object_type,created from dba_objects;

Table created.

 

创建组合索引

SQL> create index idx_dave_test_com on dave_test(owner,object_id,object_type);

Index created.

 

--收集表的统计信息

SQL> exec dbms_stats.gather_table_stats('SYS','DAVE_TEST');

PL/SQL procedure successfully completed.

 

SQL> set autot traceonly exp;

 

指定组合索引的所有字段时,使用Index range scan

SQL> select * from dave_test where owner='SYS' and object_id=20 and object_type='TABLE';

 

Execution Plan

----------------------------------------------------------

Plan hash value: 418973243

 

--------------------------------------------------------------------------------

| Id  | Operation                   | Name              | Rows  | Bytes | Cost (

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                   |     1 |    27 |     2

|   1 |  TABLE ACCESS BY INDEX ROWID| DAVE_TEST         |     1 |    27 |     2

|*  2 |   INDEX RANGE SCAN          | IDX_DAVE_TEST_COM |     1 |       |     1

--------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   2 - access("OWNER"='SYS' AND "OBJECT_ID"=20 AND "OBJECT_TYPE"='TABLE')

 

指定组合索引的2个字段时,使用的还是index range scan

SQL> select * from dave_test where owner='SYS' and object_id=20;

 

Execution Plan

----------------------------------------------------------

Plan hash value: 418973243

 

--------------------------------------------------------------------------------

| Id  | Operation                   | Name              | Rows  | Bytes | Cost (

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                   |     1 |    27 |     3

|   1 |  TABLE ACCESS BY INDEX ROWID| DAVE_TEST         |     1 |    27 |     3

|*  2 |   INDEX RANGE SCAN          | IDX_DAVE_TEST_COM |     1 |       |     2

--------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   2 - access("OWNER"='SYS' AND "OBJECT_ID"=20)

 

指定组合索引的引导列,即第一个列时,不走索引,走全表扫描

SQL> select * from dave_test where owner='SYS';

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1539627441

 

-------------------------------------------------------------------------------

| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |           | 23567 |   621K|    52   (4)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| DAVE_TEST | 23567 |   621K|    52   (4)| 00:00:01 |

-------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   1 - filter("OWNER"='SYS')

 

指定组合索引的非引导列,使用Index skip scan

SQL> select * from dave_test where object_id=20 and object_type='TABLE';

 

Execution Plan

----------------------------------------------------------

Plan hash value: 3446962311

 

--------------------------------------------------------------------------------

| Id  | Operation                   | Name              | Rows  | Bytes | Cost (

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                   |     1 |    27 |    22

|   1 |  TABLE ACCESS BY INDEX ROWID| DAVE_TEST         |     1 |    27 |    22

|*  2 |   INDEX SKIP SCAN           | IDX_DAVE_TEST_COM |     1 |       |    21

--------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   2 - access("OBJECT_ID"=20 AND "OBJECT_TYPE"='TABLE')

       filter("OBJECT_ID"=20 AND "OBJECT_TYPE"='TABLE')

 

指定组合索引的最后一列,不走索引,走全表扫描

SQL> select * from dave_test where object_type='TABLE';

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1539627441

 

-------------------------------------------------------------------------------

| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |           |  1774 | 47898 |    52   (4)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| DAVE_TEST |  1774 | 47898 |    52   (4)| 00:00:01 |

-------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   1 - filter("OBJECT_TYPE"='TABLE')

 

指定组合索引的头尾2列,不走索引:

SQL> select * from dave_test where owner='SYS' and object_type='TABLE';

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1539627441

 

-------------------------------------------------------------------------------

| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |           |   830 | 22410 |    52   (4)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| DAVE_TEST |   830 | 22410 |    52   (4)| 00:00:01 |

-------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   1 - filter("OBJECT_TYPE"='TABLE' AND "OWNER"='SYS')

 

            通过以上测试,和之前官网的说明,Index skip scan 仅是在组合索引的引导列,即第一列没有指定,并且非引导列指定的情况下。

 

            联合索引选择性更高咯,所占空间应当是比单独索引要少,因为叶节点节省了重复的rowid,当然branch节点可能稍微多一点。

禁用skip scan:

alter system set “_optimizer_skip_scan_enabled” = false scope=spfile;

 

 

 

 

 

 

整理自网络

------------------------------------------------------------------------------

Blog http://blog.csdn.net/tianlesoftware

网上资源: http://tianlesoftware.download.csdn.net

相关视频:http://blog.csdn.net/tianlesoftware/archive/2009/11/27/4886500.aspx

DBA1 群:62697716(); DBA2 群:62697977()

DBA3 群:63306533;     聊天 群:40132017

转载于:https://www.cnblogs.com/tianlesoftware/archive/2010/08/31/3610013.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

导入其他spring模块配置

列如下图中有两个spring的配置文件&#xff0c;我们想把上面的配置文件导入到下面的文件中去&#xff0c;该如何操作&#xff1a; 打开下面的配置文件&#xff0c;配置属性import,在import的resource配置上面配置文件的路径就可以了&#xff0c;如下&#xff1a; <import …

vs2019编写Linux c/c++项目

最近一直在阅读ovs的源码&#xff0c;看到用户态代码的时候&#xff0c;需要对用户态的代码进行调试&#xff0c;一开始想直接使用linux中的GDB进行调试&#xff0c;但是ovs的工程太过于复杂&#xff0c;从网上找了些文章&#xff0c;发现vs2017能够支持linux c程序的调试&…

spring属性注入的set方法注入

1、值注入 创建我们要使用的User类&#xff1a; package cn.it.bean;public class User {private String name;Overridepublic String toString() {return "User [name" name ", age" age "]";}private int age; // private Car car; // /…

系统蓝屏的几种姿势

前言 在 蓝屏&#xff08;BSOD&#xff09;转储设置&#xff0c;看本文就够了&#xff01; 这篇文章里比较详细的介绍了蓝屏转储设置。做好设置后&#xff0c;我们就可以在需要的时候使系统蓝屏了。这样我们就可以拿到一份系统转储&#xff0c;供我们分析问题了。本文介绍几种可…

nginx lua mysql 性能_深入浅出 nginx lua 为什么高性能

最近很多人问我nginx lua的优势是什么&#xff1f;为什么&#xff1f;一、同步和异步、阻塞和非阻塞如果要说清楚这个问题首先要了解&#xff1a;同步和异步、阻塞和非阻塞的关系同步&#xff1a;php、java的正常代码都是同步执行的异步&#xff1a;javascript的回调函数就是异…

求两个数字的乘积,如果大于0,说明两个数字同号,如果小于0,说明两个数字异号,如果等于0,说明其中一个是0

学了java基础东西&#xff0c;就写了这个编程&#xff0c;求两个数字的乘积&#xff0c;如果大于0&#xff0c;说明两个数字同号&#xff0c;如果小于0&#xff0c;说明两个数字异号&#xff0c;如果等于0&#xff0c;说明其中一个是0 首先程序要求我们输入两个数字&#xff0c…

处理机流水线------经典五段流水线

文章是在我遇到这部分问题时查找的所有感觉挺好的内容的整合&#xff08;全部是转载的&#xff09; 流水线基础理论就不加了&#xff0c;最新的处理器流水线处理的机制也没有&#xff08;一般以用不到&#xff09;&#xff0c;想了解去随便找个芯片厂商官网下个手册自己查。 这…

求1+2+......+100的和

如何求12…100的和&#xff1f;有很多方法&#xff0c;这里我介绍用三种循环方法去求12…100的和 方法一&#xff1a;for循环&#xff1a; 代码如下&#xff1a; /**1. 求12......100的和2. 方法1&#xff1a;for循环*/ public class Demo2 {public static void main(String[…

台湾游戏企业抢滩大陆 研发成竞争核心

近日&#xff0c;台湾游戏企业进驻大陆设立研发机构、产品同大陆企业联合运营、大陆企业的产品进入台湾联运&#xff0c;以及最新的政策新闻&#xff0c;都将大陆和台湾这对本是同根的产业兄弟推上了风口浪尖。 在正在举行的“第二届中国优秀游戏制作人评选大赛”上&#xff0c…

mysql 插入中文 ERROR 1366 (HY000): Incorrect string value: '\xE7\x8E\x9E\x97' for column

1、出现这个问题&#xff0c;是因为我们的字符编码设置出现了问题&#xff0c;用cmd打开命令终端&#xff0c;查看我们的数据库设置&#xff1a; 2、输入命令use crm&#xff08;crm是我创建的数据库,大家在修改时换成自己的数据库名即可&#xff09; 再输入&#xff1a;show …

handlersocket mysql_Mysql插件之HandlerSocket的安装、配置、使用

HandlerSocket简介HandlerSocket是针对Mysql的一个NoSQL插件&#xff0c;它作为一个守护进程工作在mysqld进程里面,接收tcp连接&#xff0c;并处理来自客户端的请求。HandlerSocket不支持SQL查询&#xff0c;作为替代&#xff0c;它支持表的简单的CRUD操作。由于下面的原因&…

java,jdk安装,配置环境变量,window10系统

1、找到我们要安装的jdk软件&#xff0c;软件下载我就不介绍了&#xff0c;jdk下载连接地址 然后安装&#xff0c;一直点下一步就可以了&#xff0c;这里不建议跟换软件目录&#xff0c;毕竟第一次用&#xff0c;出了什么错就不好弄了&#xff0c;注&#xff1a;记得软件的安装…

solr mysql数据注入_(solr系列:四)将mysql数据库中的数据导入到solr中

在前面的博文中&#xff0c;已完成了在tomcat中对solr的部署&#xff0c;为solr添加了一个自定义的core,并且引入了ik分词器。那么该如何将本地的mysql的数据导入到solr中呢&#xff1f;准备工作&#xff1a;1、mysql数据源&#xff1a;myuser库中的user表(8条数据)/*Navicat M…

Silverlight学习笔记(三):创建第一个Silverlight应用程序

在开始创建程序之前&#xff0c;还是要提一下关于Silverlight开发环境搭建的问题。如果使用VS2010&#xff0c;这可以搭建Silverlight4的开发环境。我推荐大家看这篇由大牛jv9撰写的【轻松建立Silverlight 4开发环境】。 我使用的是VS2008&#xff0c;所以要搭建的是Silverlig…

按钮旁边加一个提示_地铁站的那些“红色按钮”,你知道是干啥用的吗?乱按可能被拘留...

地铁紧急停车按钮图片来自网络位置&#xff1a;站台两侧墙壁上&#xff0c;靠近列车车头、车尾两侧。外观&#xff1a;上锁的红色四方小盒子&#xff0c;按钮为红色&#xff0c;旁边写有“紧急停车按钮”等字样。使用&#xff1a;紧急时刻击碎中间玻璃&#xff0c;按压按钮。红…

根据F12在页面中调整div的大小

我们先随便写一个div大小&#xff0c;然后在chrome浏览器打开&#xff0c;显示效果&#xff1a; #logo{border: 1px solid black;width: 1300px;height: 50px;} .top{border: blue solid 1px;width: 420px;height: 50px;float: left;}<div id"logo"><div c…

The security settings could not be applied to the database because the connection has failed安装Mysql

安装msql出现这个问题&#xff0c;&#xff0c;百度了好久才解决了问题&#xff0c;说一下怎么解决的吧 把以前安装的Mysql删除打开C盘&#xff0c;点击查看&#xff0c;然后点击隐藏的项目&#xff0c;这时候目录会出现ProgramData文件&#xff0c;然后点击这个文件&#xff…

Hibernate配置C3P0连接池(在配好基本的hibernate配置下使用)

拷贝jar包 找到我们的hibernate安装包&#xff0c;在lib目录下找到optional目录&#xff0c;打开c3p0文件&#xff0c;拷贝里面的jar包到eclipse里 写一个测试类&#xff0c;代码入下 public class C3P0Test {Testpublic void test() {Session s HabernateUtils.openSessi…

workerman json mysql_workerman-json-rpc

软件简介一款使用PHP开发的高性能Json Rpc框架&#xff0c;框架使用TCP/IP协议直接传输json数据&#xff0c;系统集成统计监控模块&#xff0c;开发部署维护非常简。workerman-json-rpc 包含了服务端和客户端。特性&#xff1a;使用PHP开发&#xff0c;与PHP紧密结合PHP 多进程…

spring boot 集合mysql_Spring boot整合mysql和druid

Spring boot整合mysql和druid集成mysql数据库引入依赖mysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-starter-jdbc添加数据库配置Spring boot项目的resources目录下的applicataion.properties# datasourcespring.datasource.urljdbc:mysql://127.0.0.1…