Oracle DBA基础教程
上QQ阅读APP看书,第一时间看更新

5.2 Oracle实现数据访问的方法

Oracle的RDBMS在访问数据时最根本上使用三种访问方法:

● 全表扫描。

● 通过ROWID。

● 使用索引。

当Oracle决定使用索引时会使用ROWID来访问数据,当没有索引或者不选择使用索引时就使用全表扫描的方式。

5.2.1 全表扫描(FULL TABLE SCAN--FTS)

在使用全表扫描时,Oracle读取表中所有的行,此时通过多块读操作可以大大减少I/O的次数,利用多块读可以大大提高全表扫描的速度,只有在全表扫描的情况下才能使用多块读。在较大的表上不建议使用全表扫描,如果读取表的数据总量超过5%~10%,那么通常进行全表扫描。并行查询可能会使得我们的路径选择采用全表扫描。

即使在表上创建了索引,是否使用该索引由Oracle根据CBO优化器计算的结果选择,用户无法干预(当然DBA可以修改参数或者SQL语句使得走索引)。

Oracle读取表中所有的行、多块读操作可以大大地减少IO的次数、利用多块读可以大大地提高全表扫描的速度、只有在全表扫描的情况下才能使用多块读。

在较大的表上不建议使用全表扫描、如果读取表的数据总量超过5%—10%,那么通常进行全表扫描。并行查询可能会使得我们的路径选择采用全表扫描,如下例所示。

例子5-1 并行查询可能会使得我们的路径选择采用全表扫描

5.2.2 通过行ID(ROWID)

对于表对象,在向表中插入数据时隐含会创建该行的ROWID,ROWID是数据行所存储的数据块地址,这样就以最快的速度找到该行数据。如下例所示,查询行ID,我们通过比较,看全表扫描和通过行ID哪个更快。

ROWID指出了数据文件、块号、行号,通过ROWID是Oracle数据库中读取单行数据最快速的方法。这种方法不是采用多块读,而是采用单块读的方式。

例子5-2 查询行ID比较全表扫描和通过行ID哪个更快

5.2.3 使用索引

通过索引找到数据行的ROWID,然后通过ROWID直接到表中查找数据,这种方式称为索引查找或索引扫描。由于一个ROWID对应一个数据行,因此这种方式采用的也是单块读。在索引中,除了存储每个索引值,还存储相应的ROWID,索引扫描分为两步:

01 扫描索引得到相应的ROWID。

02 通过找到的ROWID从表中读取相应的数据,

每次采用的都是单块I/O读,由于索引小,而且经常使用,因此通常被cache到内存中,并且第一步通常是逻辑读(数据可以从内存中得到),由于表数据比较大,因此第二步通常是物理读,并且性能较低。

索引改进性能的程度取决于两个因素:

● 数据的选择性。

● 表数据在数据块上的分布。

如果选择性很高(例如身份证号码),则根据索引值返回的ROWID很少,如果选择性很低(例如国家)则返回的ROWID很多,那么索引的性能将会大大降低(返回的数据少,I/O压力小)。

如果选择性很高,但是相关的行在表中的存储位置并不互相靠近,则会进一步减少索引的益处,如果匹配索引值的数据分散在表的多个数据块中,则必须从表中选择多个单独的块以满足查询,基于索引的读取是单块读取,如果使用全表扫描,使用的是多块读取以便快速扫描表,因此全表扫描不见得比索引扫描速度慢,关键看数据对象数据块的分散程度。

当访问的行数较少时,SELECT、UPDATE、DELETE+WHERE条件可以从索引中得到更多的好处。一般来说,增加索引会带来insert语句性能的下降,如果根据未索引列update索引列,那么也会带来性能的降低。大量的delete也会因为索引的存在而导致性能降低。因此我们要分析具体的情况,判断索引和DML语句之间的关系。

通过索引找到数据行的ROWID、然后通过ROWID直接到表中查找数据,这种方式称为索引查找或者索引扫描。因为一个ROWID对应一个数据行,因此这种方式采用的也是单块读。在索引中,除了存储每个索引值、还存储相应的ROWID,索引扫描分为两步:

01 扫描索引得到相应的ROWID。

02 通过找到的ROWID从表中读取相应的数据。

每次采用的都是单块IO读,因为索引小,而且经常使用,因此通常被cache到内存中,因此第一步通常是逻辑读(数据可以从内存中得到),因为表数据比较大、因此第二步读通常是物理读,因此性能较低。

例子5-3 访问路径走主键索引的查询

访问路径走的是主键索引,因此是INDEX UNIQUE SCAN,首先是索引扫描,然后是根据索引查找到的ROWID进行表的访问。