简介: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带来的排序。