执行计划-数据访问方式(全表扫描与4种索引的方式)

执行计划

Oracle执行计划的相关概念:

Rowid:系统给oracle数据的每行附加的一个伪列,包含数据表名称,数据库id,存储数据库id以及一个流水号等信息,rowid在行的生命周期内唯一。

Recursive sql:为了执行用户语句,系统附加执行的额外操作语句,譬如对数据字典的维护等。

Row source(行源):oracle执行步骤过程中,由上一个操作返回的符合条件的行的集合。

Predicate(谓词):where后的限制条件。

Driving table(驱动表):又称为连接的外层表,主要用于嵌套与hash连接中。一般来说是将应用限制条件后,返回较少行源的表作为驱动表。在后面的描述中,将driving table称为连接操作的row source 1。

Probed table(被探查表):连接的内层表,在我们从driving table得到具体的一行数据后,在probed table中寻找符合条件的行,所以该表应该为较大的row source,并且对应连接条件的列上应该有索引。在后面的描述中,一般将该表称为连接操作的row source 2.

Concatenated index(组合索引):一个索引如果由多列构成,那么就称为组合索引,组合索引的第一列为引导列,只有谓词中包含引导列时,索引才可用。

可选择性:表中某列的不同数值数量/表的总行数如果接近于1,则列的可选择性为高。

————————————————————————————————————————

Oracle访问数据的存取方法:

1. Full table scans, FTS(全表扫描):

通过设置db_block_multiblock_read_count可以设置一次IO能读取的数据块个数,从而有效减少全表扫描时的IO总次数,也就是通过预读机制将将要访问的数据块预先读入内存中。只有在全表扫描情况下才能使用多块读操作。

2. Table access by rowed(通过rowid存取表,rowid lookup):

由于rowid中记录了行存储的位置,所以这是oracle存取单行数据的最快方法。

3. Index scan(索引扫描index lookup):

在索引中,除了存储每个索引的值外,索引还存储具有此值的行对应的rowid值,索引扫描分两步1,扫描索引得到rowid;2,通过 rowid读取具体数据。每步都是单独的一次IO,所以如果数据经限制条件过滤后的总量大于原表总行数的5%-10%,则使用索引扫描效率下降很多。而如果结果数据能够全部在索引中找到,则可以避免第二步操作,从而加快检索速度。

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

3.1 Index unique scan(索引唯一扫描):

存在unique或者primary key的情况下,返回单个rowid数据内容。

3.2 Index range scan(索引范围扫描):

1,在唯一索引上使用了range操作符(>,<,<>,>=,<=,between);2,在组合索引上,只使用部分列进行查询;3,对非唯一索引上的列进行的查询。

3.3 Index full scan(索引全扫描):

需要查询的数据从索引中可以全部得到。

3.4 Index fast full scan(索引快速扫描):

与index full scan类似,但是这种方式下不对结果进行排序。

实验:

SQL> create table school(sid number(4),sname varchar2(400 char), check_status number(1) default 0 check( check_status in(0,1)),accountant varchar2(20 char)unique,pwd varchar2(20 char),email varchar2(30 char),photo_path varchar2(800 char),
constraint pk_t_school primary key(sid));
Table created.

SQL> create sequence shool_sid_autoinc
minvalue 1
maxvalue 9999999999999999999999999999
start with 1
increment by 1
nocache;

SQL> create or replace trigger insert_shool_sid_autoinc
before insert on school
for each row
begin
select shool_sid_autoinc.nextval into :new.sid from dual;
end;
/

SQL> create table team(sid number(4),tid number(2),tname varchar2(400 char),number_of_teams number(2),mentor varchar2(400 char),constraint pk_t_team primary key(tid),constraint fk_t_school01 foreign key(sid) references school(sid));
Table created.

SQL> create sequence team_tid_autoinc
minvalue 1
maxvalue 9999999999999999999999999999
start with 1
increment by 1
nocache;

SQL> create or replace trigger insert_team_tid_autoinc
before insert on team
for each row
begin
select team_tid_autoinc.nextval into :new.tid from dual;
end;
/

-- 重复插入十三条记录(sid不一样)
SQL> insert into school values(3,‘aaaaaaaaaaaaaaaaaaaaa‘,0,001,001,‘[email protected]‘,66666);
SQL> insert into school values(4,‘aaaaaaaaaaaaaaaaaaaaa‘,0,001,001,‘[email protected]‘,66666);
.......
SQL> insert into school values(15,‘aaaaaaaaaaaaaaaaaaaaa‘,0,001,001,‘[email protected]‘,66666);
SQL> set autotrace on;

1. Full table scans, FTS(全表扫描)

SQL> select * from school;
Execution Plan
----------------------------------------------------------
Plan hash value: 149184061

----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1306 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| SCHOOL | 1 | 1306 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------

2. Table access by rowed(通过rowid存取表,rowid lookup)

SQL> select rowid from school;

ROWID
------------------
AAATdsAAEAAAADHAAA
AAATdsAAEAAAADHAAB
AAATdsAAEAAAADHAAC
AAATdsAAEAAAADHAAD
AAATdsAAEAAAADHAAE
AAATdsAAEAAAADHAAF
AAATdsAAEAAAADHAAG
AAATdsAAEAAAADHAAH
AAATdsAAEAAAADHAAI
AAATdsAAEAAAADHAAJ
AAATdsAAEAAAADHAAK
AAATdsAAEAAAADHAAL
AAATdsAAEAAAADHAAM

13 rows selected.

SQL> select * from school where rowid=‘AAATdsAAEAAAADHAAA‘;
Execution Plan
----------------------------------------------------------
Plan hash value: 2354595538

-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1318 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY USER ROWID| SCHOOL | 1 | 1318 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------

3.1 Index unique scan(索引唯一扫描)

SQL> select * from school where sid=3;
Execution Plan
----------------------------------------------------------
Plan hash value: 3749557451

-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1306 | 0 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| SCHOOL | 1 | 1306 | 0 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_T_SCHOOL | 1 | | 0 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

3.2 Index range scan(索引范围扫描)

SQL> select sid from school where sid<8;

Execution Plan
----------------------------------------------------------
Plan hash value: 3257910080

--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 0 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| PK_T_SCHOOL | 1 | 13 | 0 (0)| 00:00:01 |
--------------------------------------------------------------------------------

3.3 Index full scan(索引全扫描)

SQL> select sid from school;

Execution Plan
----------------------------------------------------------
Plan hash value: 2759332510

--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 0 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_T_SCHOOL | 1 | 13 | 0 (0)| 00:00:01 |
--------------------------------------------------------------------------------

3.4 Index fast full scan(索引快速扫描)

SQL> create index in_t_school_sid_sname on school(sid,sname);
SQL> select * from school where sname=‘aaaaaaaaaaaaaaaaaaaaa‘;
Execution Plan
----------------------------------------------------------
Plan hash value: 2494086730

-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1306 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| SCHOOL | 1 | 1306 | 2 (0)| 00:00:01 |
|* 2 | INDEX SKIP SCAN | IN_T_SCHOOL_SID_SNAME | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

总结:
当进行index full scan的时候,oracle定位到索引的root block,然后到branch block(如果有的话),
再定位到第一个leaf block, 然后根据leaf block的双向链表顺序读取。它所读取的块都是有顺序的,也是经
过排序的。而index fast full scan则不同,它是从段头开始,读取包含位图块,root block,所有的branch
block,leaf block,读取的顺序完全由物理存储位置决定,并采取多块读,数据是无序的,每次读取
db_file_multiblock_read_count个块。这就是为什么两者的结果区别如此之大的原因。

OK,转载请标明出处
————————————————————————————————————————

时间: 2024-12-21 18:01:43

执行计划-数据访问方式(全表扫描与4种索引的方式)的相关文章

【大数据课堂0008】会引起全表扫描的几种SQL 以及sql优化

查询语句的时候尽量避免全表扫描,使用全扫描,索引扫描!会引起全表扫描的几种SQL如下 1.模糊查询效率很低: 原因:like本身效率就比较低,应该尽量避免查询条件使用like:对于like ‘%...%’(全模糊)这样的条件,是无法使用索引的,全表扫描自然效率很低:另外,由于匹配算法的关系,模糊查询的字段长度越大,模糊查询效率越低. 解决办法:首先尽量避免模糊查询,如果因为业务需要一定要使用模糊查询,则至少保证不要使用全模糊查询,对于右模糊查询,即like ‘…%’,是会使用索引的:左模糊lik

表访问方式----&gt;全表扫描(Full Table Scans, FTS)

全表扫描(Full Table Scans, FTS) 全表扫描是指Oracle在访问目标表里的数据时,会从该表所占用的第一个区(EXTENT)的第一个块(BLOCK)开始扫描,一直扫描到该表的高水位线(HWM,High Water Mark),Oracle会对这期间读到的所有数据施加目标SQL的where条件中指定的过滤条件,最后只返回那些满足过滤条件的数据. 不是说全表扫描不好,事实上Oracle在做全表扫描操作时会使用多块读,ORACLE采用一次读入多个数据块 (database bloc

SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析

原文:SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析 在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index Seek))呢?是否所有情况都是如此?又该如何优化呢? 下面我们通过一些简单的例子来分析理解这些现象.下面的实验环境为SQL SERVER 2008,如果在不同版本有所区别,欢迎指正. 堆表单索引 首先我们构建我们测试需要实验环境,

为什么全表扫描成本(COST)公式里面要除以sreadtim

全表扫描的成本计算公式 如下: Cost = ( #SRds * sreadtim + #MRds * mreadtim + CPUCycles / cpuspeed ) / sreadtim 全表扫描的时候,单块读次数=0,#SRds表示单块读次数.全表扫描的成本里面,CPU消耗其实非常少,可以忽略不计,所以全表扫描的公式可以改写为: Cost = #MRds * mreadtim / sreadtim #MRds 表示多块读io次数 mreadtim 表示一次多块读耗费时间 sreadtim

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

1.Oracle访问表的方式 全表扫描.通过ROWID访问表.索引扫描 2.全表扫描(Full Table Scans, FTS) 为实现全表扫描,Oracle顺序地访问表中每条记录,并检查每一条记录是否满足WHERE语句的限制条件.ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描,而不是只读取一个数据块,这极大的减少了I/O总次数,提高了系统的吞吐量,所以利用多块读的方法可以十分高效地实现全表扫描.需要注意的是只有在全表扫描的情况下才能使用多块读操作.在这种

SQL 数据优化索引建suo避免全表扫描

首先什么是全表扫描和索引扫描?全表扫描所有数据过一遍才能显示数据结果,索引扫描就是索引,只需要扫描一部分数据就可以得到结果.如果数据没建立索引. 无索引的情况下搜索数据的速度和占用内存就会比用索引的检索慢和高.下面是一个例子 1:无索引的情况 Product表,里面没有任何索引,如下图: 从上图中,我悲剧的看到了,物理读是9次,也就说明走了9次硬盘,你也可以想到,走硬盘的目的是为了拿数据,逻辑读有1636次,要注意的是这里 的”次“是“页”的意思,也就是在内存中走了1636个数据页,我用dbcc

怎么对10亿数据量级的mongoDB作高效的全表扫描

转自:http://quentinxxz.iteye.com/blog/2149440 一.正常情况下,不应该有这种需求 首先,大家应该有个概念,标题中的这个问题,在大多情况下是一个伪命题,不应该被提出来.要知道,对于一般较大数据量的数据库,全表查询,这种操作一般情况下是不应该出现的,在做正常查询的时候,如果是范围查询,你至少应该要加上limit. 说一下,我的应用场景:用于全量建立搜索引擎的索引.这就是一种需要用到全表扫描的非一般情况.对于全表扫描的结果,我们没有排序要求. 二.情况说明 既然

避免全表扫描的sql优化

对查询进行优化,应尽量避免全表扫描,首先应考虑在where 及order by 涉及的列上建立索引:  .尝试下面的技巧以避免优化器错选了表扫描: ·   使用ANALYZE TABLE tbl_name为扫描的表更新关键字分布. ·   对扫描的表使用FORCE INDEX告知MySQL,相对于使用给定的索引表扫描将非常耗时.            SELECT * FROM t1, t2 FORCE INDEX (index_for_column)             WHERE t1.

如何导致全表扫描原因

转一位大神的笔记. 导致表的执行计划做全表扫描的原因: u       SQL谓词列没有建相应的索引 u       谓词列建有相应的索引,但执行计划没有使用 Oracle不使用b*tree索引的情况大致如下 1:where条件中和null比较可能导致不使用索引 2:count,sum,ave,max,min等聚集操作时可能导致不使用索引 3:显示或者隐式的函数转换导致不使用索引 4:在cbo模式下,统计信息过于陈旧导致不使用索引 5:组合索引中没有使用前导列导致没有使用索引 6:访问的数据量超