oracle排序、回表扫描和联合索引

简介:oracle回表扫描也会增加IO消耗,有的时候可以通过一些方法避免。如果对索引的结构还不太理解,可以看一下我以前的博客,oracle树状索引详解。

一.oracle回表扫描

例子:test 表 10w数据,10个字段,主键为id

1.select * from test where id = 5

回表扫描介绍:执行这个sql的执行计划,可以看到,首先它走了主键的索引,可以看到一个index range scan,并且还有一个table access by index rowid,这个就是回表扫描了。执行流程是这样的,先从id索引块里找到id=5的数据,由于索引里只有id的值,要拿到其他列值,需要通过索引里的rowid去表里检索到这一列的其他字段。

那怎么可以优化呢?根据自己需求来看。

首先确定自己需不需要表里全部的字段,如果不需要全部的,

第一步,可以把sql改为:

例如:select id,name,amount from test where id = 5,这样可以少拿字段,优化了一点点。

第二步,根据需求建立联合索引

当你这几个字段经常要用到查询,可以在这几个字段上建立联合索引,这个索引就有 id,name,amount 三列(通常不建议超过3列,因为索引也是很占空间的,多了得不偿失,而且更新的时候还要更新索引,影响效率)

建好这个索引之后,还是同样的道理,这个查询语句就可以在这个索引块里找到所有的值,就不需要去扫描很多数据块了,建好索引,我们再看一下执行计划,就没有table access by index rowid了,耗费的IO也是变少了(可以看cost和逻辑读有体现)

当不能避免回表扫描的时候怎么办呢?回表扫描肯定也会有快和慢。

第一点:根据索引返回的数据条数越少,回表扫描根据rowid去找数据次数更少,肯定也会更快。

第二点:跟数据块的分布位置也会有关系。

例子:select * from test where id <10

如果数据分布是有序的,1-9是在一个索引块里面,然后对应数据块也是有序的,这个sql回表扫描数据的时候,只需要扫描一个数据块。如果是无序的,1-9在多个索引块分布,数据也分布在多个数据块,回表扫描数据就需要多扫描很多数据块。

总结:对于回表扫描,能避免最好,不能避免的话,索引尽量优化,返回的数据条数尽量少,回表扫描就会快一点。

表的插入顺序和索引列的顺序基本一致,在回表的时候就会更快。

二.order by 的优化

由于排序是很消耗性能的,要优化 我们可以利用索引是有序的这个特点,比如很多情况下会有create_time这个字段,有索引的排序可以利用索引排序,就能达到消除排序的目的。

ps:distinct之所以消耗性能也是因为去重之前需要先排序,所以如果distinct的字段有索引的话,也是可以消除distinct带来的排序。



你可能感兴趣的:(oracle)