要寫出高效的SQL,那麼必須必須得清楚SQL執行路徑,介紹如何提高SQL性能的文章很多,這裡不再贅述,本人來談談如何從 減少SQL回表次數 來提高查詢性能,因為回表將導致掃描更多的數據塊。
我們大家都知道,數據庫表中數據存儲都是以塊為單位,稱為數據塊;表中每行數據都有唯一的地址標誌ROWID。
舉個例子:
select a from test_db where b=5
A、假設b上沒有索引
1、那麼該條SQL將進行表掃描,掃描所有該表的數據塊
2、從數據塊中找到記錄,並且進行過濾
可想而知,沒有索引將會導致掃描該表所有數據塊,性能低下
B、 假設b上有索引
1、那麼該條SQL將進行索引掃描,在索引中找到b=5的位置,一般只需要掃描3個塊左右就找到了
2、獲得所有b=5的行的rowid
3、根據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
我們分析一下(假設索引是b,c,a):
1、先查詢內層語句 select * from table t where b=? and c=?,假設返回1000行數據
2、通過索引找到這1000行數據的rowid,因為索引是連續的,假設這1000行數據的索引分布在5個塊中,則差不多為8塊讀
3、再根據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
再來分析一下:
1、最裡層的sqlselect rid from (selectrowidrid,row_numberover(order by a)rnfrom table where b=? And c=?) wherern>=1 andrn<=20 可以全部從索引中獲得數據,由於索引有序,差不多也是8塊讀
2、分頁之後,只有20行數據,再根據這20行的rowid回表查詢數據,最壞情況是20行都在20個不同塊中,那麼總共20+8=28
從以上分析可以看出,有效的利用索引,減少回表次數,可以大大提高SQL性能,值得大家去花功夫了解一下。