sql 語句的limit的用法(轉載)

sql 語句的limit的用法(轉載)

SELECT * FROM table  LIMIT [offset,] rows | rows OFFSET offset   mysql> SELECT * FROM table LIMIT 5,10;  // 檢索記錄行 6-15
None.gif
//爲了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個參數爲 -1:
None.gifmysql> SELECT * FROM table LIMIT 95,-1; // 檢索記錄行 96-last.
None.gif
None.gif//如果只給定一個參數,它表示返回最大的記錄行數目:
None.gifmysql> SELECT * FROM table LIMIT 5;     //檢索前 5 個記錄行
None.gif
None.gif//換句話說,LIMIT n 等價於 LIMIT 0,n。select * from table LIMIT 5,10; #返回第6-15行數據
select * from table LIMIT 5; #返回前5行
select * from table LIMIT 0,5; #返回前5行


1、offset比較小的時候。
select * fromyanxue8_visit limit 10,10

多次運行,時間保持在0.0004-0.0005之間

Select * From yanxue8_visit Where vid >=(
Select vid From yanxue8_visit Order By vid limit 10,1
) limit 10


多次運行,時間保持在0.0005-0.0006之間,主要是0.0006
結論:偏移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條記錄
第1句執行結果.100 rows in set (0.23) sec
第2句執行結果.100 rows in set (0.19) sec

很明顯第2句勝出.看來limit好像並不完全像我之前想象的那樣做全表掃描返回limitoffset+length條記錄,這樣看來limit比起MS-SQL的Top性能還是要提高不少的.

其實第2句完全可以簡化成

Select * From cyclopedia Where ID>=(
Select ID From cyclopedia limit 90000,1
)limit 100;

直接利用第90000條記錄的ID,不用經過Max運算,這樣做理論上效率因該高一些,但在實際使用中幾乎看不到效果,因爲本身定位ID返回的就是1條記錄,Max幾乎不用運作就能得到結果,但這樣寫更清淅明朗,省去了畫蛇那一足.

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

第1種方案同樣可用於MS-SQL,而且可能是最好的.因爲靠主鍵ID來定位起始段總是最快的.

Select Top 100 * From cyclopedia Where ID>=(
Select Top 90001 Max(ID) From (
Select ID From cyclopedia Order By ID
) As tmp
)

但不管是實現方式是存貯過程還是直接代碼中,瓶頸始終在於MS-SQL的TOP總是要返回前N個記錄,這種情況在數據量不大時感受不深,但如果成百上千萬,效率肯定會低下的.相比之下MySQL的limit就有優勢的多,執行:
Select ID From cyclopedia limit 90000
Select ID From cyclopedia limit 90000,1
的結果分別是:
90000 rows in set (0.36) sec
1 row in set (0.06) sec
而MS-SQL只能用Select Top 90000 ID From cyclopedia執行時間是390ms,執行同樣的操作時間也不及MySQL的360ms.----------------------------------------------------------LIMIT 思考 PERCONA PERFORMANCE CONFERENCE 2009上,來自雅虎的幾位工程師帶來了一篇”EfficientPagination Using MySQL“的報告,有很多亮點,本文是在原文基礎上的進一步延伸。首先看一下分頁的基本原理:mysql> explain SELECT * FROM message ORDER BYid DESC LIMIT 10000, 20G
***************** 1. row **************
id: 1
select_type: SIMPLE
table: message
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
rows: 10020
Extra:
1 row in set (0.00 sec)limit10000,20的意思掃描滿足條件的10020行,扔掉前面的10000行,返回最後的20行,問題就在這裏,如果是limit100000,100,需要掃描100100行,在一個高併發的應用裏,每次查詢需要掃描超過10W行,性能肯定大打折扣。文中還提到limitn性能是沒問題的,因爲只掃描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數據總量的表中測試,效果非常明顯。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章