本文首發於我的微信公衆號《andqian》,期待你的關注!mysql
前面寫了《讀懂MySQL執行計劃》和《寫會MySQL索引》後,今天咱們來講說MySQL中另一個比較重要的概念,就是 LIMIT 關鍵字。面試
LIMIT的概念,其實你們應該都很清楚,在百度百科中是這樣描述的:sql
LIMIT是一種數據語言,主要是用於查詢以後要顯示返回的前幾條或者中間某幾行數據。微信
這裏着重須要注意的是: offset爲開始角標,count表明數量,以下圖所示:數據結構
(圖片來源: mysqltutorial)優化
理解了這個概念以後,咱們就可以知道下面這兩個語句的意思了:spa
LIMIT 0,100; (A)
LIMIT 10,100; (B)索引
語句A表明的是 : 從起始角標爲0的位置,日後獲取100條記錄。圖片
語句B表明的是 : 從起始角標爲10的位置,日後獲取100條記錄。開發
(別覺得這很簡單,在以前的面試過程當中,就有不少童鞋搞混了,將語句B理解成了: 從起始角標爲10的位置,獲取90條數據呢。)
其實,LIMIT還有一個比較經常使用的簡化寫法,以下所示:
LIMIT 100;
這其實就是對上述A語句的簡化,其意思表明的是: 從其實角標爲0的位置,日後獲取100條記錄。只是將其實角標0省略掉了而已。正是由於這樣的特性,有不少應用也直接使用LIMIT來進行分頁操做。
上面咱們介紹了,LIMIT的概念,也理清楚了LIMIT每一個參數的含義,那如今就留一個問題:
問: LIMIT 0,100與 LIMIT 100000,100的執行效率是同樣嗎? 同樣爲何?不同又爲何?
ps: 在Java面試時會常常問到哦。我以前就被問到過。
咱們都知道, LIMIT通常是跟在order by xx asc|desc語句後的,接下來咱們就來看看下面這兩個語句,一塊兒來分析一下上述問題的答案:
語句A:
select * from t_base_user order by oid desc limit 0,100;
語句B:
select * from t_base_user order by oid desc limit 10000,100;
分別看下執行計劃:
語句A的執行計劃是:
explain select * from t_base_user order by oid desc limit 0,100;
結果:
語句B的執行計劃是:
explain select * from t_base_user order by oid desc limit 10000,100;
結果:
到這裏,咱們會發現掃描的行數是徹底不同的,在語句B中,其實MySQL實際掃描1000100行記錄,而後只返回100條記錄,將前面的1000000條記錄活生生的拋棄掉,你說這成本大不大,代價高不高? 看到這裏,咱們應該已經知道上面問題的答案了。
如今咱們來講說如何優化LIMIT,咱們知道,在offset比較大的時候,效率會很是低,因此,對LIMIT優化,要麼限制分頁的數量,要麼下降offset的大小。 例如:
select * from t_base_user limit 100000,100
好比上面這語句,由於咱們主鍵是連續的。
方法一 : 咱們就能夠經過這樣來優化:
select * from t_base_user where oid between 100000 and 1000100;
此時若是咱們看執行計劃的話,其實type已經從all(全表掃描)掃描優化到range(範圍查找),也走了PRIMARY索引。
方法二: 咱們能夠倒序LIMIT 若是咱們表中一共有120萬數據,此時咱們就能夠倒序LIMIT,以下所述:
select * from t_base_user order by oid desc limit 100;
或者這樣:
select * from t_base_user where oid<1000000 order by oid desc limit 100;
一樣也達到來優化的效果。
本文全部數據,均基於如下數據結構:
create table t_base_user(
oid bigint(20) not null primary key auto_increment,
name varchar(30) null comment "name",
email varchar(30) null comment "email",
age int null comment "age",
telephone varchar(30) null comment "telephone",
status tinyint(4) null comment "0 無效 1 有效",
created_at datetime null default now() comment "建立時間",
updated_at datetime null default now() comment "修改時間"
)
// 新增記錄: insert into t_base_user(name,email,age,telephone,status,created_at,updated_at) values ("andyqian","andytohome",20,"15608411",1,now(),now());
這裏提供一個簡單的方法複製數據
insert into t_base_user(name,email,age,telephone,status) select name,email,age,telephone,status from t_base_user;
使用該語句,能夠快速的複製數據。執行屢次後,就可以生成很多數據,(備註: 該數據僅用做LIMIT關鍵字演示,新建索引,計算區分度其值誤差會比較大,請勿將該結果做爲建索引的參考值。)
上面對MySQL LIMIT關鍵字作了詳細的講解,你可別小瞧它哦,它在平時開發中有很大的用處哦,例如: 在平時開發查詢數據時,加上LIMIT後,查詢效果可會大大增長,能節省很多時間呢。在查詢數據時養成加上LIMIT是一個不錯的習慣。
最後: 祝你們晚安!
相關閱讀:
掃碼關注,一塊兒進步
我的博客: http://www.andyqian.com