【Mysql】使用子查詢提高MySQL分頁效率 limit(摘自網絡)


 

1.LIMIT n 等價於 LIMIT 0,n 偏移offset較小的時候,直接使用limit較優。

2offset大的時候。
select * from yanxue8_visit limit 10000,10
多次運行,時間保持在0.0187左右

Select * From yanxue8_visit Where vid >=(
Select vid From yanxue8_visit Order By vid limit 10000,1
) limit 10
多次運行,時間保持在0.0061左右,只有前者的1/3。可以預計offset越大,后者越優

性能優化:基於MySQL5.0中limit的高性能,我對數據分頁也重新有了新的認識.

1.
Select * From cyclopedia Where ID>=(Select Max(ID) From (Select ID From cyclopedia Order By ID limit90001) As tmp) limit 100;
2.
Select * From cyclopedia Where ID>=(Select Max(ID) From ( Select ID From cyclopedia Order By ID limit90000,1) As tmp) limit 100;

同樣是取90000條后100條記錄,第1句快還是第2句快?
第1句是先取了前90001條記錄,取其最大ID值作為起始,然后快速定位下100條記錄
第2句擇是僅僅取90000條記錄后1條,然后取ID值作起始標識定位下100條記錄
很明顯第2句勝出.看來limit好像並不完全像我之前想象的那樣做全表掃描返回limit offset+length條記錄,這樣看來limit比起MS-SQLTop性能還是要提高不少的.


可是,既然MySQL有limit可以直接控制取出記錄的位置,為什么不干脆用Select * From cyclopedia limit90000,1呢?  豈不更簡潔?
這樣想就錯了,試了就知道,結果是:1 row in set (8.88)sec,怎么樣,夠嚇人的吧,讓我想起了昨天在4.1中比這還有過之的"高分" .Select *最好不要隨便用,要本着用什么,選什么的原則, Select的字段越多,字段數據量越大,速度就越慢.上面2種分頁方式哪種都比單寫這1句強多了,雖然看起來好像查詢的次數更多一些,但實際上是以較小的代價換取了高效的性能,是非常值得的.

靠主鍵ID來定位起始段總是最快
但不管是實現方式是存貯過程還是直接代碼中,瓶頸始終在於MS-SQLTOP總是要返回前N個記錄,這種情況在數據量不大時感受不深,但如果成百上千萬,效率肯定會低下的.相比之下MySQL的limit就有優勢的多,執行:

LIMIT 思考

 

PERCONA PERFORMANCE CONFERENCE 2009上,來自雅虎的幾位工程師帶來了一篇”EfficientPagination Using MySQL“的報告,有很多亮點,本文是在原文基礎上的進一步延伸。首先看一下分頁的基本原理:

limit10000,20的意思掃描滿足條件的10020行,扔掉前面的10000行,返回最后的20,問題就在這里,如果是limit100000,100,需要掃描100100行,在一個高並發的應用里,每次查詢需要掃描超過10W行,性能肯定大打折扣。文中還提到limit n性能是沒問題的,因為只掃描n行。

文中提到一種”clue”的做法,給翻頁提供一些線索,比如還是SELECT * FROM message ORDER BYidDESC,按id降序分頁,每頁20條,當前是第10頁,當前頁條目id最大的是9527,最小的是9500,如果我們只提供”上一頁”、”下一頁”這樣的跳轉(不提供到第N頁的跳轉),那么在處理”上一頁”的時候SQL語句可以是:

SELECT * FROM message WHERE id > 9527 ORDER BYid ASC LIMIT 20;

處理”下一頁”的時候SQL語句可以是:

SELECT * FROM message WHERE id < 9500 ORDER BYid DESC LIMIT 20;

不管翻多少頁,每次查詢只掃描20行。

缺點是只能提供”上一頁”、”下一頁”的鏈接形式,但是我們的產品經理非常喜歡”<上一頁 1 23 4 5 6 7 8 9 下一頁>”這樣的鏈接方式,怎么辦呢?

如果LIMIT m,n不可避免的話,要優化效率,只有盡可能的讓m小一下,我們擴展前面的”clue”做法,還是SELECT *FROM message ORDER BY idDESC,id降序分頁,每頁20條,當前是第10頁,當前頁條目id最大的是9527,最小的是9500,比如要跳到第8頁,我看的SQL語句可以這樣寫:

SELECT * FROM message WHERE id > 9527 ORDER BYid ASC LIMIT 20,20;

跳轉到第13頁:

SELECT * FROM message WHERE id < 9500 ORDER BYid DESC LIMIT 40,20;

原理還是一樣,記錄住當前頁id的最大值和最小值,計算跳轉頁面和當前頁相對偏移,由於頁面相近,這個偏移量不會很大,這樣的話m值相對較小,大大減少掃描的行數。其實傳統的limitm,n,相對的偏移一直是第一頁,這樣的話越翻到后面,效率越差,而上面給出的方法就沒有這樣的問題。

注意SQL語句里面的ASC和DESC,如果是ASC取出來的結果,顯示的時候記得倒置一下。已在60W數據總量的表中測試,效果非常明顯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM