这篇是整理复习oracle关于访问表数据的方法,在oracle数据库中,要想访问存储在数据库中的数据,
要依次经历下面几个步骤:
待执行的SQL ----> 解析 ----> 优化器处理 ----> 生成执行计划 ----> 实际执行 ----> 返回执行结果,
其中,在优化器的处理这个阶段,来决定访问目标表数据的方式,即优化器要采用什么方式去访问具体
的数据。
在oracle中访问表的方式分为两种,一种是直接访问表,一种是先访问索引,再回表(当然,还有可能
只访问索引就可以得到数据,这样的话,就不需要回表了)。
下面就分别整理出上述两种访问表中数据的方法。
1.访问表的方法
直接访问表中数据的方法有两种: 全表扫描和ROWID扫描。
1.1 全表扫描
oracle在访问目标表里面的数据时,会从该表所占用的第一个区(EXTENT)的第一个块(BLOCK)开始扫
描,一直扫描到该表的高水位线(HWM,High Water Mark),最后返回满足where条件的数据。
析:全表扫描时候会使用多块读,在目标表数据量不大的时候,效率是很高的,但问题在于,全表扫
描执行时间不稳定、不可控,执行时间会随着数据量递增而递增;
1.2 ROWID扫描
rowid扫描是指oracle在访问数据时,是通过数据所在的物理存储地址去定位并访问数据。
对于oracle里的堆表来说,可通过oracle内置的rowid伪列得到对应行记录所在的rowid的值。然后通过
DBMS_ROWID包里面的相关方法将rowid伪列翻译成为对应数据行的实际物理存储地址,如下
select empno,ename,rowid,dbms_rowid.rowid_relative_fno(rowid)||'_'||
dbms_rowid.rowid_block_number(rowid)||'_'||dbms_rowid.rowid_row_number(rowid)
from emp;
2.访问索引的方法
这里说的是oracle数据库中最常用的B树索引,B树索引类似一颗倒长的树,包含两种类型的数据块,
一种是索引分支块,一种是索引叶子块。
B树索引的优势有三点
a. 所有索引叶子块层在同一层,它们距离索引根节点的深度相同,意思就是访问索引叶子块的任何
索引键值所花费的时间几乎相同;
b. oracle会保证所有的B树索引都是自平衡的,不可能出现不同的索引叶子块不处于同一层的现象;
c. 通过B树索引访问表里记录的效率并不会随着相关表的数据量的递增而明显降低,也就是说通过
走索引访问数据的时间是可控的、基本稳定的,这也是走索引和全表扫描的最大区别;
下面是oracle里面的常见的访问B树索引的方法介绍
2.1 索引唯一性扫描
索引唯一性扫描(INDEX UNIQUE SCAN)是针对唯一性索引(UNIQUE INDEX)的扫描,不过呢它仅
仅适用于where条件里等值查询类SQL,由于扫描对象是唯一性索引,所以扫描结果至多返回一条记
录。
2.2 索引范围扫描
索引范围扫描(INDEX RANGE SCAN)适用于所有类型的B树索引,当扫描对象是唯一性索引时,目
标SQL的where条件一定是范围查询(谓词条件为BETWEEN、<、>等);当扫描对象是非唯一性索引
时候,对目标SQL的where条件没有限制(可以是等值查询,也可以是范围查询)。
2.3 索引全扫描
索引全扫描(INDEX FULL SCAN)适用于所有类型的B树索引,指的是要扫描目标索引所有必要分支
块下的叶子块的所有索引行。默认情况下,oracle在做索引全扫描时候只需要通过访问定位到位于该
索引最左边的叶子块的第一行索引行,然后利用该索引叶子块之间的双向指针链表,从左到右依次顺
序扫描该索引所有叶子块的所有索引行。
索引全扫描的前提条件是,目标索引至少有一个索引键值列的属性是NOT NULL。
默认情况下,索引全扫描要从左到右依次顺序扫描目标索引所在叶子块的所有索引行,由于索引是
有序的,所以索引全扫描的执行结果也是有序的,并且是按照索引的索引键值列来排序,由此可见,
走索引全扫描在能够达到排序的效果,同时避免了对该索引的索引键值列的真正排序操作,这个情况
可以在SQL时,在索引全扫描的执行计划中查看sorts(memory),sorts(disk)是否为0来确认。
索引全扫描的结果有序性,决定了索引全扫描不能并行执行,并且通常情况下是单块读。
2.4索引快速全扫描
索引快速全扫描(INDEX FAST FULL SCAN)和索引全扫描类似,有如下几个区别:
a. 只适用于CBO
b. 可以使用多块读,也可以并行执行
c. 执行结果不一定是有序的
2.5索引跳跃式扫描
索引跳跃式扫描(INDEX SKIP SCAN)适用于所有类型的复合B树索引(包括唯一性索引和非
唯一性索引),跳跃的意思是,比如表DEMO1有字段(gender varchar2(1),id number not null),然
后给该表创建一个复合B树索引如下
create index idx_xxx on demo1(gender,id);
然后给表以下面形式插入多行记录
begin
for i in 1..5000 loop
insert into demo1 values('F',i);
end loop
commit;
end;
/
begin
for i in 5001..10000 loop
insert into demo1 values('M',i);
end loop
commit;
end;
/
然后,打开执行计划执行一条查询
set autotrace traceonly
select * from demo1 where id = 100;
在执行计划中可以看到用上了索引idx_xxx
而上面where条件是id=100,即它只对复合索引的第二列指定了查询条件,并没有对前导列
指定查询条件,这就是索引跳跃扫描的情况。其实这个是oracle会对前导列的所有distinct值
做遍历。
索引跳跃式扫描效率会随着目标索引前导列的distinct值的递增而效率递减,所以它仅适用
于目标索引的前导列的distinct值数量较少、后续非前导列的可选择性又非常好的情况下。
表的表数据的方法这块到此整理完毕,后续有时间最好能每个点都举例来整理。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。