· 直接访问表中的数据,即;全表扫描。
· 先访问相应的索引获取相应的ROWID,再通过该ROWID访问表中对应的数据(回表),即:索引扫描+回表。
一、全表扫描
1.全表扫描的定义
Oracle数据库的全表扫描是指访问表中数据时,从该表在表空间中的第一个Extent中的第一个BLOCK开始访问,一致到该表的HWM(高水位线,High Water Mark)为止,该范围内的所有BLOCK均需要读取到SGA的Buffer Cache中。
如果执行查询的SQL语句指定了过滤条件(where条件),在访问过程中将进行过滤,并最终返回符合条件记录。
需要注意的是,即使第一条数据就满足条件,Oracle数据库仍会继续扫描剩余的数据,直到扫描完所有BLOCK为止。
Oracle数据库的执行计划中,关于全表扫描的描述为:TABLE ACCESS FULL。
2.全表扫描的性能分析
Oracle数据库在执行全表扫描时采用多块读的方式(这种方式一般为从SGA的Buffer Cache中读取,即:逻辑读或一致性读),在待查询的表的数据量不大的情况下,这种访问方式的效率是比较高的。
但是,表中的数据可能会逐渐增加,随着数据的增加,表的HWM也是逐渐递增的,这将导致对表执行全表扫描时所需要访问的BLOCK越来越多,I/O开销不断上涨,最后,相应SQL语句的执行时间将变长。
全表扫描可能导致Oracle数据库出现db file scattered read等待事件。
3.HWM对全表扫描性能的影响
对于Oracle数据库,在对一个表经常插入数据的情况下,如果存储占用量达到分配给该表的当前空间上限,此时该表的HWM将向上移动,即使使用了DELETE删除了数据,已经向上移动的HWM也不会收缩,如图1所示。
图1 HWM示意图
由此可知,即使使用了DELETE删除了表中的大部分数据,HWM还是停留在原来的位置,这时,采用全表扫描访问表时,仍需访问HWM之下的所有BLOCK。这就是一些表在删除大量数据后,其查询性能仍未改善的一个原因。
二、ROWID扫描
Oracle数据库的ROWID扫描是指访问表中的数据时,直接通过数据对应的ROWID进行定位和获取。
ROWID代表了ORACLE数据库中数据行所对应的物理存储地址。
Oracle数据库中的堆表存在一个名为ROWID的伪列,可以通过ROWID伪列得到数据行对应的ROWID的值,图2展示了ROWID伪列的值。
图2 ROWID伪列的值
Oracle数据库的执行计划中,关于ROWID扫描的描述注意要有TABLE ACCESS BY USER ROWID和TABLE ACCESS BY INDEX ROWID两大类。
· TABLE ACCESS BY USER ROWID:在SQL语句的过滤条件(where)中直接使用了ROWID。
· TABLE ACCESS BY INDEX ROWID:首先通过索引定位到待访问的数据记录获取相应的ROWID,之后通过该ROWID去表中访问该数据行,这就是所谓的回表访问。
三、索引扫描
1.B-Tree索引简介
B-Tree索引是Oracle数据库常用的索引之一,其采用了B-Tree数据结构,图3是一个B-Tree索引的示例。
图3 B Tree索引示例图
如图3所示,B-Tree索引包含两种类型的节点,即:分支节点和叶子节点。
B-Tree索引的分支节点包含指向相应索引分支或叶子节点的指针和和对应的索引键值列,通过图3可知,索引的键值列可以并非是完整的索引键值,其可能只是一个前缀,只要Oracle数据库可以根据前缀列区分出相应的索引分支或叶子节点即可。这样就可以快速定位其下层的索引分支或叶子节点了。
在B-Tree中,最顶层的节点是根节点,Oracle数据库访问B-Tree索引时均从根节点开始。
B-Tree索引的叶节点存放着该索引的键值和记录该索引对应的数据行在标记物理存储位置的ROWID。此外,为了便于访问,所有的叶节点均用双相指针进行关联,组成一个双向列表。
2.B-Tree索引对表访问性能的影响
根据上述对B Tree索引的介绍可知B-Tree索引对表访问性能的影响有着如下的影响。
(1)B-Tree索引中,所有的叶节点均在同一层,因此,这些叶节点距离根节点的深度都是相同的。所以,访问索引叶节点中的任何一个索引键值所产生的时间开销基本是相同的;
(2)Oracle数据库确保B-Tree索引是平衡的,不会出现不同的索引的叶节点分布在不同层的问题,且多数情况下,Oracle数据库将B-Tree索引的深度控制在2或者3,使得在索引中找到一个键只需要2或3次I/O即可,确保了访问效率;
(3)通过B-Tree索引访问数据行的效率不会随着表中数据量的增加而明显下降,这是索引扫描与全表扫描在访问性能上的最大区别。
再次强调,通过B-Tree索引扫描数据时,Oracle数据库首先访问B-Tree索引,之后根据得到的ROWID回表访问相应的数据行。这两步操作均需要一定的I/O开销,所以,索引扫描的成本主要由从B-Tree根节点至分支节点再到叶节点获取ROWID的B-Tree遍历成本和通过ROWID到表中获取对应的数据行所属的BLOCK的访问成本两部分组成。
本文节选自第七十八期《51测试天地》
《Oracle数据库表数据的访问方式》一文
想继续阅读全文或查看更多精彩内容,请点击下载:
版权声明:本文出自《51测试天地》第七十八期。51Testing软件测试网及相关内容提供者拥有51testing.com内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任。