ORACLE回表(一)

要写出高效的SQL,那么必须必须得清楚SQL执行路径,介绍如何提升SQL性能的文章不少,这里再也不赘述,本人来谈谈如何从 减小SQL回表次数 来提升查询性能,由于回表将致使扫描更多的数据块。sql

   咱们你们都知道,数据库表中数据存储都是以块为单位,称为数据块;表中每行数据都有惟一的地址标志ROWID。数据库

  举个例子:性能

    select a from test_db where b=5spa

   A、假设b上没有索引orm

         一、那么该条SQL将进行表扫描,扫描全部该表的数据块索引

         二、从数据块中找到记录,而且进行过滤it

      可想而知,没有索引将会致使扫描该表全部数据块,性能低下table

  B、 假设b上有索引test

        一、那么该条SQL将进行索引扫描,在索引中找到b=5的位置,通常只须要扫描3个块左右就找到了select

        二、得到全部b=5的行的rowid

        三、根据rowid再查询数据(这就是回表),若是数据量少,那么回表次数就少,若是须要的数据所有在索引中,那么就不会再回表了,例如a也在索引中,若是a不在索引中,那么仍然要回表一次查出a。

   


     经验:若是有可能的话,尽可能只在索引上查询,不用回表或者只少许回表。

       

     例如分页须要回表,通常尽可能在索引上分页,而后返回rowid,再经过rowid进行回表查询。

    下面是一个经常使用的分页语句:


   Select * from (select row_number over(order by a) rn,t.* from table t where b=? And c=?) where rn>=1 and rn <=20   
Select * from (select row_number over(order by a) rn,t.* from table t where b=? And c=?) where rn>=1 and rn <=20

 咱们分析一下(假设索引是b,c,a):

   一、先查询内层语句 select * from table t where b=? and c=?,假设返回1000行数据

   二、经过索引找到这1000行数据的rowid,由于索引是连续的,假设这1000行数据的索引分布在5个块中,则差很少为8块读

   三、再根据rowid取回表查询数据,最坏的状况是这1000行数据分布在1000个块中,则须要读取1000块。那么算上上面的8块总共尧都区1000+8=1008块

咱们换一种写法:

 Select * from table t,   
(select rid from (select rowid rid,row_number over(order by a) rn from table where b=? And c=?)   
 where rn>=1 and rn<=20) tmp   
Where tmp.rid=t.rowid   
Select * from table t,
(select rid from (select rowid rid,row_number over(order by a) rn from table where b=? And c=?)
 where rn>=1 and rn<=20) tmp
Where tmp.rid=t.rowid

再来分析一下:

  一、最里层的sql select rid from (select rowid rid,row_number over(order by a) rn from table where b=? And c=?) where rn>=1 and rn<=20 能够所有从索引中得到数据,因为索引有序,差很少也是8块读

 二、分页以后,只有20行数据,再根据这20行的rowid回表查询数据,最坏状况是20行都在20个不一样块中,那么总共20+8=28

   

  从以上分析能够看出,有效的利用索引,减小回表次数,能够大大提升SQL性能,值得你们去花功夫了解一下。

相关文章
相关标签/搜索