MYSQL查詢優化:Limit

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

2、offset大的時候。
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-SQL的Top性能還是要提高不少的.


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

靠主鍵ID來定位起始段總是最快
但不管是實現方式是存貯過程還是直接代碼中,瓶頸始終在於MS-SQL的TOP總是要返回前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數據總量的表中測試,效果非常明顯。


http://www.cnblogs.com/zack-/archive/2012/04/17/mysql_limit_efficiency.html

發佈了37 篇原創文章 · 獲贊 12 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章