要写出高效的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性能,值得你们去花功夫了解一下。