现在的位置: 首页 > 数据库 > 正文

Oracle数据访问方法之全表扫描与索引扫描介绍

2014年11月09日 数据库 ⁄ 共 3243字 暂无评论 ⁄ 阅读 3,059 次
文章目录

生成执行计划的下一个步骤就是利用优化器来确定访问数据的最好方法。访问数据有两种基本的数据访问途径:全扫描(全表扫描或快速全索引扫描)或索引扫描。

在全扫描过程中,多个块被读入到一个IO运算中。索引扫描通过扫描索引叶子块来取得特定的ROWID,然后利用这些ROWID来访问父表取得实际的行数据,而这些访问都是通过单块读取来完成的。

全扫描

当对一个对象(表或索引)进行全扫描时,与该对象相关的所有数据块都必须取出并进行处理,以确定块中所包含的数据行是否是你的查询所需要的。在读取数据块时,会将其整体读取到内存中以取得块中所存储的数据行的数据。

因此,在发生全扫描时,优化器及我们需要考虑两件事:必须读取多少个数据块以及每个数据块中有多少数据将被舍弃

全扫描与物理存储

经验主义者讲,当结果集占表20%~70%时最好使用全扫描。然而,有时这并不正确。可能1%的数据也需要全扫描,而返回数据行百分比很高可能也不应该全表扫描。

例如:对于两个表T1和T2,T1中数据等值比较聚集T2中数据等值较为分散,我们需要表中1%的数据。

对于T1表最好使用索引扫描,因为值比较聚集可能仅需要访问较少的块就能得到结果集(磁盘读取一个块后,由于块会缓存在缓冲区,这样就避免了更多的物理IO)。

而对于T2表,由于数据较分散,在使用索引时可能将极少进行逻辑读,它将大量的进行单块读。此时,采用索引所耗费的时间可能比全表扫描读取所有数据块然后将每个数据块中不需要的数据舍弃所花的时间更长。

由此可见,数据的物理存储方式将影响扫描方式。

全扫描与舍弃

全扫描是否高效取决于需要访问的数据块个数以及最终的结果集行数(舍弃的行数)。舍弃的行是那些通过筛选谓语验证,被证明是不符合筛选条件而被从结果集中剔除的数据行。

虽然采用多块读的全扫描占用IO较少,但为了筛选结果集完成每一行的检查却需要花费相当多的CPU资源,而CPU的使用将会归入全扫描成本中。所访问数据块数目以及舍弃的数量越大,全表扫描的成本也就越高。

若你感觉优化器所选择并非最佳计划,也可以使用提示来强制使用索引或不使用索引。

统计数据行和数据块信息:

SELECT TABLE_NAME,NUM_ROWS,BLOCKS FROM USER_TABLES WHERE TABLE_NAME = ‘table_name’;

注意,数据字典中存储数据均采用大写方式。

全扫描与多块读

使用全扫描时,一个单独的IO调用将会请求多个块而不是一个,所请求数目是可变的,它从1到参数db_file_multiblock_read_count。例如,这个参数是16,而表中有160个块,则仅需要10次IO就可以获取所有块。

全扫描与高水位线

对于某个段,当有数据删除时,高水位线并不会自动降低。此时,虽然数据块是空的,但在全扫描时仍然会被读取,这将会造成性能的降低。

索引扫描

通过索引获取每一行,将至少需要访问两个数据块:至少一个索引叶子块和一个数据块。具体来讲,对于索引高度是n的索引,需要访问n个索引块,再加一个数据块。

索引扫描类型包括索引唯一扫描、索引范围扫描、索引全扫描、索引跳跃扫描以及索引快速全扫描。

聚簇因子

之前讲过,Oracle选择全表扫描还是索引会根据表的物理存储方式确定。那到底是如何确定的呢,这叫要说说一个非常重要的索引统计信息——聚簇因子(clustering factor)了(聚簇因子针对非唯一索引?)。

索引的聚簇因子向优化器表明了具有同样索引值的数据行是不是存放在同一个或连续的一系列数据块中,或者说数据行是否被分散存放在表的多个数据块中。聚簇因子越低,基于索引值的数据行聚合度越高,反之越低。

查看聚簇因子可使用以下语法:

select a.index_name,a.clustering_factor,b.num_rows,b.blocks

from user_indexes a, user_tables b

where index_name = 'index_name'

and a.table_name = b.table_name;

聚簇因子是通过每次当前行的块编号与前一行的块编号不同时对计数器加一来进行计算的。当聚簇因子不合适时,我们不能通过重建索引来“修正”,因为聚簇因子与索引无关而是与表中数据行相关。若想通过重建表来改进聚簇因子,也需要注意,若表有多个索引,可能你重建表使其适合了一个索引却影响了其他列上的索引。

索引唯一扫描

当谓语中使用列包含UNIQUE或PRIMARY KEY索引的列作为条件时就会选用索引唯一扫描,这种索引能保证对于某个特定的值只返回一行数据。

执行计划中的TABLE ACCESS BY INDEX ROWID表明了表通过索引访问,INDEX UNIQUE SCAN表明使用索引唯一扫描。

索引范围扫描

当谓语中包含将会返回一定范围数据的条件时就会选用索引范围扫描。索引可以是唯一的或者不唯一的,因为是由该条件来确定是否会返回多个数据行的。所指定的条件可以使用如<、>、LIKE、BETWEEN、=等运算符。

在执行计划中INDEX RANGE SCAN表明使用索引范围扫描。

范围扫描从根数据块开始找到第一个符合特定条件的叶子数据块来遍历索引,从这点开始从索引条件中取出一个ROWID(标明了数据文件、段编号和块编号)然后取出相应的表数据块。在第一行被取出以后,之前的叶子索引块将再一次被访问并读取下一个索引条目来获取下一个ROWID。这种索引叶子块和表数据块之间的反复读取将直到所有匹配的索引条目都被读出。因此,在计算访问块数时使用“返回行数”乘以2,再加上blevel(分枝层级,比索引高度小1)。例如,使用范围扫描返回5行数据并且blevel为3,则总共需要访问的数据块为(5*2)+3=13。

另外,由于索引的升序排列特点。有时候即使使用全表扫描可能更合理,优化器也会选择使用索引来访问数据行。这种情况通常发生在ORDER BY子句使用列是索引列的时候。因为索引升序排列的特点,使用索引读取数据意味着数据行是按照一定顺序来获取的,可以避免再单独做一次排序处理。

索引全扫描

当有以下情况时使用索引全扫描:

  • 没有谓语但select列表中其中一列有索引;
  • 谓语中包含一个位于索引中非引导列上的条件;
  • 数据可以通过一个排过序的索引来获取并且会省去单独的排序步骤;

在执行计划中INDEX FULL SCAN表明使用索引全扫描。

索引全扫描运算将会扫描索引结构中的每一个叶子块,读取每个条目的ROWID,并取出数据行。这通常比全表扫描效率高,因为每一个索引块要比表数据块包含更多的条目,从而总的需要访问的块数也就相应较少。(疑问:这里就不会读一个ROWID访问一个块了?

另外,索引全扫描还有个优势就是在查询某列的最大值或最小值时,使用索引全扫描只需要扫描第一个或最后一个叶子块即可。但需要注意的是,当同时有max()和min()运算时,优化器将不能采用索引全扫描,这是优化器的一个不足之处。

索引跳跃扫描

在组合索引中,当谓语包含位于索引中非引导列上的条件,并且引导列的值是唯一(个人注解:有等值存在且不只一个等值)的时候会选择索引跳跃扫描。

在执行计划中INDEX SKIP SCAN表明使用索引跳跃扫描。

跳跃扫描逻辑上将组合索引分解为较小的子索引,逻辑子索引的数目取决于引导列唯一值个数。引导列唯一值越多,需要建立的逻辑子索引越多,运算效率越差。但是,在逻辑子索引较少时,索引跳跃扫描较全表扫描效率更高。因为扫描较小索引块的效率要比扫描较大表数据块效率高。

索引快速全扫描

索引快速全扫描更像全表扫描而不像其他类型的索引扫描。所有索引块通过多块读的方式进行。当select列表中列全在索引中并且索引中至少有一列具有非空约束时会采用索引快速全扫描替换全表扫描,然而,这种扫描方式并不能避免排序。

在执行计划中INDEX FULL SCAN表明使用索引快速全扫描。

声明:该笔记转载自《Oracle SQL高级编程》,仅用于个人学习,若侵犯到您的版权敬请告知!

» 声明:本站文章源于个人经验总结或书籍、互联网转载,内容仅用于个人学习,请勿转载,否则后果自负!

给我留言

留言无头像?