执行计划-数据访问方式(全表扫描与4种索引的方式)
2016-12-27 21:34
489 查看
执行计划
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,'964955634@qq.com',66666);
SQL> insert into school values(4,'aaaaaaaaaaaaaaaaaaaaa',0,001,001,'964955634@qq.com',66666);
.......
SQL> insert into school values(15,'aaaaaaaaaaaaaaaaaaaaa',0,001,001,'964955634@qq.com',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,转载请标明出处
————————————————————————————————————————
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,'964955634@qq.com',66666);
SQL> insert into school values(4,'aaaaaaaaaaaaaaaaaaaaa',0,001,001,'964955634@qq.com',66666);
.......
SQL> insert into school values(15,'aaaaaaaaaaaaaaaaaaaaa',0,001,001,'964955634@qq.com',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,转载请标明出处
————————————————————————————————————————
相关文章推荐
- 执行计划-数据访问方式(全表扫描与4种索引的方式)
- 写一条SQL,使它通过全表扫描方式的效率优于索引访问,分别给出各自的执行计划。
- Oracle性能分析5:数据访问方式之索引结构和扫描方式介绍
- Oracle性能分析6:数据访问方式之索引扫描
- oracle编程入门笔记2015-01-18--执行计划中的索引扫描方式说明
- 执行计划中常见index访问方式(转)
- 【转自Oracle ACE-盖国强】Oracle 11g全表扫描以Direct Path Read方式执行
- Oracle 11g全表扫描以Direct Path Read方式执行
- 清除SQL Server数据缓存和执行计划缓存,查看执行计划的各种方式对比
- Oracle 执行计划(5)—cost成本之索引范围扫描-B树索引
- Oracle 全表扫描及其执行计划(full table scan)
- 第六章——根据执行计划优化性能(2)——查找表/索引扫描
- oracle执行计划(4.5)--cost成本之快速索引扫描
- Oracle 11g全表扫描以Direct Path Read方式执行
- 清除SQL Server数据缓存和执行计划缓存,查看执行计划的各种方式对比
- 【性能优化案例】执行计划宁可走全表扫描,也不走索引
- 使用Oracle9i全索引扫描快速访问数据
- 使用Oracle9i全索引扫描快速访问数据
- Oracle的HINT可以强制指定SQL的执行计划,比如选择索引、表的连接顺序以及表的连接方式等等。(转)
- 清除SQL Server数据缓存和执行计划缓存,查看执行计划的各种方式对比