mysql分页limit运算,MySQL的limit分页查询及性能问题
MySQL 通過 limit 實(shí)現(xiàn)分頁(yè)查詢。limit 接收一個(gè)或兩個(gè)整數(shù)型參數(shù)。如果是兩個(gè)參數(shù),第一個(gè)指定返回記錄行的偏移量,第二個(gè)指定返回記錄行的最大數(shù)目。初始記錄行的偏移量是 0。為了與 PostgreSQL 兼容,limit 也支持limit a offset b【a:取的記錄數(shù);b:索引】。
一、分頁(yè)查詢
客戶端通過傳遞 start(頁(yè)碼),pageSize(每頁(yè)顯示的條數(shù))兩個(gè)參數(shù)去分頁(yè)查詢數(shù)據(jù)庫(kù)表中的數(shù)據(jù)。MySql 數(shù)據(jù)庫(kù)提供的分頁(yè)函數(shù) limit m,n 用法和實(shí)際需求不切合,所以就需要根據(jù)實(shí)際情況去改寫適合分頁(yè)的語(yǔ)句。
1??查詢第1條到第10條的數(shù)據(jù)select * from table limit 0,10;
--->對(duì)應(yīng)需求就是查詢第一頁(yè)的數(shù)據(jù):select * from table limit (1-1)*10,10;
2??查詢第11條到第20條的數(shù)據(jù)select * from table limit 10,10;
--->對(duì)應(yīng)需求就是查詢第二頁(yè)的數(shù)據(jù):select * from table limit (2-1)*10,10;
3??查詢第21條到第30條的數(shù)據(jù)select * from table limit 20,10;
--->對(duì)應(yīng)需求就是查詢第三頁(yè)的數(shù)據(jù):select * from table limit (3-1)*10,10;
由此,得出符合需求的分頁(yè) sql 格式是:select * from table limit (start-1)*pageSize,pageSize;其中 start 是頁(yè)碼,pageSize 是每頁(yè)顯示的條數(shù)。
二、性能問題
對(duì)于小的偏移量,直接用 limit 查詢沒有什么問題。隨著數(shù)據(jù)量的增大,越往后分頁(yè),limit 語(yǔ)句的偏移量越大,速度也會(huì)明顯變慢。
優(yōu)化思想:
避免數(shù)據(jù)量大時(shí)掃描過多的記錄
解決:
子查詢的分頁(yè)方式或者 JOIN 分頁(yè)方式。JOIN 分頁(yè)和子查詢分頁(yè)的效率基本在一個(gè)等級(jí)上,消耗的時(shí)間也基本一致。
一般 MySQL 的主鍵是自增的數(shù)字類型,這種情況下可以使用下面的方式進(jìn)行優(yōu)化。以真實(shí)的生產(chǎn)環(huán)境的6萬(wàn)條數(shù)據(jù)的一張表為例,比較一下優(yōu)化前后的查詢耗時(shí):
-- 傳統(tǒng) limit,文件掃描
select * from table order by id limit 50000,2;
受影響的行: 0
時(shí)間: 0.171s
-- 子查詢方式,索引掃描
select * from table
where id >= (select id from table order by id limit 50000 , 1)
limit 2;
受影響的行: 0
時(shí)間: 0.035s
-- JOIN 分頁(yè)方式
select * from table as t1
join (select id from table order by id limit 50000, 1) as t2
where t1.id <= t2.id order by t1.id limit 2;
受影響的行: 0
時(shí)間: 0.036s
可以看到經(jīng)過優(yōu)化性能提高了很多倍。
優(yōu)化原理:
子查詢是在索引上完成的,而普通的查詢是在數(shù)據(jù)文件上完成的。通常來(lái)說,索引文件要比數(shù)據(jù)文件小得多,所以操作起來(lái)也會(huì)更有效率。因?yàn)橐〕鏊凶侄蝺?nèi)容,普通查詢需要跨越大量數(shù)據(jù)塊并取出,而另一種方式直接根據(jù)索引字段定位后,才取出相應(yīng)內(nèi)容,效率自然大大提升。因此,對(duì) limit 的優(yōu)化,是避免直接使用 limit,而是首先獲取到 offset 的 id,然后直接使用 limit size 來(lái)獲取數(shù)據(jù)。
在實(shí)際項(xiàng)目使用,可以利用類似策略模式的方式去處理分頁(yè)。例如,每頁(yè) 100 條數(shù)據(jù),判斷如果是 100 頁(yè)以內(nèi),就使用最基本的分頁(yè)方式;如果大于 100,則使用子查詢的分頁(yè)方式。
三、limit 優(yōu)化。使用合理的分頁(yè)方式以提高分頁(yè)的效率
使用 limit 實(shí)現(xiàn)分頁(yè)邏輯。不僅提高了性能,同時(shí)減少了不必要的數(shù)據(jù)庫(kù)和應(yīng)用間的網(wǎng)絡(luò)傳輸。
查詢結(jié)果只有一條或者只要最大/最小一條記錄,建議用 limit 1。這是為了使 explain 中 type 列達(dá)到 const 類型。“l(fā)imit 1”可以避免全表掃面,只要找到了對(duì)應(yīng)的一條記錄,就不會(huì)繼續(xù)向下掃描了,效率將會(huì)大大提高。當(dāng)然,如果查詢字段是唯一索引的話,沒必要加 limit 1,因?yàn)?limit 的存在主要就是為了防止全表掃描,從而提高性能,如果一個(gè)語(yǔ)句本身可以預(yù)知不用全表掃描,有沒有 limit ,性能的差別并不大。
使用下面 SQL 語(yǔ)句做分頁(yè)的時(shí)候,隨著表數(shù)據(jù)量的增加,直接使用 limit 分頁(yè)查詢會(huì)越來(lái)越慢。
select id,name from product limit 89757, 20
優(yōu)化如下:可以取前一頁(yè)的最大行數(shù)的 id,然后根據(jù)這個(gè)最大的 id 來(lái)限制下一頁(yè)的起點(diǎn)。此列中,上一頁(yè)最大的 id 是 89756。SQL 可以采用如下的寫法:
//方案一 :返回上次查詢的最大記錄(偏移量)
select id,name from product where id> 89756 limit 20
//方案二:order by + 索引
select id,name from product order by id limit 10000,10
//方案三:在業(yè)務(wù)允許的情況下限制頁(yè)數(shù)
理由如下:
當(dāng)偏移量最大的時(shí)候,查詢效率就會(huì)越低,因?yàn)?MySQL 并非是跳過偏移量直接去取后面的數(shù)據(jù),而是先把偏移量+要取的條數(shù),然后再把前面偏移量這一段的數(shù)據(jù)拋棄掉再返回的。
如果使用優(yōu)化方案一,返回上次最大查詢記錄(偏移量),這樣可以跳過偏移量,效率提升不少。
方案二使用 order by+索引,也是可以提高查詢效率的。
方案三的話,建議跟業(yè)務(wù)討論,有沒有必要查這么多的分頁(yè)。因?yàn)榻^大多數(shù)用戶都不會(huì)往后翻太多頁(yè)。
【強(qiáng)制】 在代碼中寫分頁(yè)查詢邏輯時(shí),若 count 為 0 應(yīng)直接返回,避免執(zhí)行后面的分頁(yè)語(yǔ)句。
總結(jié)
以上是生活随笔為你收集整理的mysql分页limit运算,MySQL的limit分页查询及性能问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php九宫格代码,用php数字九宫格.
- 下一篇: c语言数据库线程池,C语言多线程中运行线