select * from table limit [offset,] rows | rows offset offset mysql> select * from table limit 5,10; // 檢索記錄行 6-15
//為了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個參數為 -1:
mysql> select * from table limit 95,-1; // 檢索記錄行 96-last.
//如果隻給定一個參數,它表示傳回最大的記錄行數目:
mysql> select * from table limit 5; //檢索前 5 個記錄行
//換句話說,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 vid from yanxue8_visit order by vid limit 10000,1
多次運作,時間保持在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 id from cyclopedia order by id limit90000,1
同樣是取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 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
)
但不管是實作方式是存貯過程還是直接代碼中,瓶頸始終在于ms-sql的top總是要傳回前n個記錄,這種情況在資料量不大時感受不深,但如果成百上千萬,效率肯定會低下的.相比之下mysql的limit就有優勢的多,執行:
select id from cyclopedia limit 90000
的結果分别是:
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資料總量的表中測試,效果非常明顯。