天天看點

sql 語句的limit的用法

select * from table  limit [offset,] rows | rows offset offset   mysql> select * from table limit 5,10;  // 檢索記錄行 6-15

sql 語句的limit的用法

//為了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個參數為 -1: 

sql 語句的limit的用法

mysql> select * from table limit 95,-1; // 檢索記錄行 96-last.

sql 語句的limit的用法
sql 語句的limit的用法

//如果隻給定一個參數,它表示傳回最大的記錄行數目: 

sql 語句的limit的用法

mysql> select * from table limit 5;     //檢索前 5 個記錄行

sql 語句的limit的用法
sql 語句的limit的用法

//換句話說,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資料總量的表中測試,效果非常明顯。