Mysql中深分頁的五種常用方法整理
在數(shù)據(jù)量非常大的情況下,深分頁查詢則變得很常見,深分頁會導(dǎo)致MySQL需要掃描大量前面的數(shù)據(jù),從而效率低下。例如,使用LIMIT 100000, 10時,MySQL需要掃描前100000條數(shù)據(jù)才能找到第10000頁的數(shù)據(jù)。
在MySQL中解決深分頁問題,可通過以下5種優(yōu)化方案實(shí)現(xiàn):
方案一:延遲關(guān)聯(lián) (Deferred Join)
原理:先通過子查詢獲取主鍵,再關(guān)聯(lián)原表獲取完整數(shù)據(jù)
通常我們直接查詢分頁較大的數(shù)據(jù)速率較慢,我們可以選擇優(yōu)先查詢主鍵列,因?yàn)槠淇梢酝ㄟ^索引查詢且速度最快,然后根據(jù)獲取的主鍵匹配對應(yīng)的數(shù)據(jù)。
SELECT t.* FROM user t INNER JOIN ( SELECT id FROM user ORDER BY sort_field LIMIT 100000, 10 ) AS tmp ON t.id = tmp.id;
方案二:有序唯一鍵分頁 (Cursor-based Pagination)
要求:表中存在有序唯一鍵(如自增ID)
這種方法的原理就是我們在進(jìn)行范圍查詢后需要記錄頁尾的行號,當(dāng)查詢以行號開始的范圍數(shù)據(jù)時直接根據(jù)行號匹配,避免了掃描前面的數(shù)據(jù)。
-- 假設(shè)已知上一頁最后一條記錄的id為12345 SELECT * FROM user WHERE id > 12345 ORDER BY id LIMIT 10;
方案三:書簽分頁 (Bookmark Pagination)
原理:記錄上一頁最后一條數(shù)據(jù)的排序字段值
-- 假設(shè)按create_time排序,上一頁最后記錄的create_time為'2023-01-01 12:00:00' SELECT * FROM user WHERE create_time > '2023-01-01 12:00:00' ORDER BY create_time LIMIT 10;
方案四:預(yù)估分頁 (Approximate Pagination)
適用場景:允許誤差的近似分頁
適用于數(shù)據(jù)量極大的場景,即主鍵也不再進(jìn)行分頁查詢,而是通過預(yù)估得到大致行號的范圍,再通過主鍵匹配數(shù)據(jù)行(此方案可能會有誤差,需要根據(jù)場景選擇)
-- 先獲取預(yù)估偏移量 SELECT COUNT(*) FROM user WHERE sort_field < {target_value}; -- 再使用延遲關(guān)聯(lián)獲取精確數(shù)據(jù) SELECT t.* FROM user t INNER JOIN ( SELECT id FROM user WHERE sort_field < {target_value} ORDER BY sort_field LIMIT 10 ) AS tmp ON t.id = tmp.id;
方案五:緩存優(yōu)化 (Caching)
適用場景:高頻訪問的固定排序分頁
- 對常用排序方式預(yù)生成分頁結(jié)果
- 使用Redis等緩存中間結(jié)果
- 查詢時優(yōu)先讀取緩存數(shù)據(jù)
性能對比(100萬數(shù)據(jù)測試)
方案 | 傳統(tǒng)LIMIT | 延遲關(guān)聯(lián) | 有序唯一鍵 | 書簽分頁 |
---|---|---|---|---|
1000頁查詢耗時 | 2.3s | 420ms | 8ms | 12ms |
內(nèi)存占用 | 高 | 中 | 低 | 低 |
最佳實(shí)踐建議
1.優(yōu)先使用有序唯一鍵分頁(如自增ID),時間復(fù)雜度從O(n)降至O(1)
2.對高頻查詢的排序字段建立索引
3.結(jié)合業(yè)務(wù)場景選擇方案:
- 實(shí)時性要求高 → 方案二/三
- 數(shù)據(jù)量極大 → 方案四/五
- 允許誤差 → 方案四
4.對超過10萬條數(shù)據(jù)的分頁需求,建議改用滾動加載(無限下拉)模式
方法補(bǔ)充
下面小編為大家整理了一些Mysql深度分頁優(yōu)化的其他思路和方案,希望對大家有所幫助
1.普通分頁的優(yōu)化方法
一般分頁不是很深的情況下,我們一般可以通過以下方法解決大部分的分頁問題
通過增加主鍵排序,例如:order by id
如果需要根據(jù)時間排序,就給常用的字段增加索引,包括時間字段。例如:order by create_time
以上兩種手段其實(shí)可以解決大部分的分頁問題了。但是如果后面的頁數(shù)很深了,比如從100w條開始取20條,我們就會發(fā)現(xiàn)再執(zhí)行sql語句就會非常慢,這是因?yàn)閙ysql的優(yōu)化器在發(fā)現(xiàn)sql查詢的行數(shù)超過一定比例的時候,就會自動轉(zhuǎn)換成全表掃描,可以自己模擬數(shù)據(jù)測試一下。
什么是Mysql的深度分頁?
查詢偏移量過大的分頁的場景我們稱為深度分頁,例如以下sql語句就是一個典型的深度分頁場景
SELECT * FROM t_xxx ORDER BY id LIMIT 1000000, 20
2.深度分頁的優(yōu)化方案
強(qiáng)制索引 force index(不推薦)
一開始想著使用force index強(qiáng)制走索引,但是我的leader跟我說過,不建議添加強(qiáng)制索引來進(jìn)行sql優(yōu)化,主要有以下幾種缺點(diǎn):
- 影響選擇性最佳的索引:強(qiáng)制使用索引可能會影響數(shù)據(jù)庫引擎選擇性最佳的索引,導(dǎo)致查詢性能下降
- 增加更新操作的時間:強(qiáng)制使用索引后,數(shù)據(jù)庫更新操作的時間會增加,因?yàn)樗饕募枰桓?/li>
- 降低查詢的靈活性:如果強(qiáng)制使用索引過于固定,會降低查詢的靈活性,不方便后期維護(hù)。
ID范圍查詢
如果那種不需要頁碼的場景下,比如滑動加載(消息列表這種),還有那種只有上下頁按鈕點(diǎn)擊的網(wǎng)站分頁,我們可以通過where id > #{上次查詢的最后一條記錄的id} 進(jìn)行優(yōu)化
# 查詢指定 ID 范圍的數(shù)據(jù) SELECT * FROM t_xxx WHERE id > 1000000 AND id <= 1000020 ORDER BY id # 也可以通過記錄上次查詢結(jié)果的最后一條記錄的ID進(jìn)行下一頁的查詢 SELECT * FROM t_xxx WHERE id > 1000000 LIMIT 20
子查詢+INNER JOIN
可以先根據(jù)時間字段(create_time)或者id排序查詢到id,比如:
SELECT id FROM t_xxx ORDER BY create_time DESC LIMIT 1000000,20
這個子查詢先查出來,作為臨時表,然后再讓主表join這個臨時表去聯(lián)表查詢需要的t_xxx對應(yīng)的信息字段,這樣也可以達(dá)到一個很好的效果,最終sql語句就是這樣:
SELECT * FROM t_xxx INNER JOIN (SELECT id FROM t_xxx WHERE name = 'xxx' ORDER BY id LIMIT 1000000,20) AS t_temp ON t_xxx.id = t_temp.id
子查詢+ID過濾
也可以通過子查詢+ID過濾優(yōu)化的方式進(jìn)行優(yōu)化,例如:
SELECT * FROM t_xxx WHERE name = 'xxx' AND id >(SELECT id FROM t_xxx WHERE name = 'xxx' ORDER BY id LIMIT 1000000,1) ORDER BY id LIMIT 20
到此這篇關(guān)于Mysql中深分頁的五種常用方法整理的文章就介紹到這了,更多相關(guān)Mysql深分頁內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql批量刪除數(shù)據(jù)方法及注意事項(xiàng)說明
這篇文章主要介紹了mysql批量刪除數(shù)據(jù)方法及注意事項(xiàng)說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01windows下MySQL免安裝版配置教程mysql-5.6.51-winx64.zip版本(最新安裝教程)
這篇文章主要介紹了windows下MySQL免安裝版配置教程mysql-5.6.51-winx64.zip版本(最新安裝教程),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-01-01MySQL創(chuàng)建和刪除表操作命令實(shí)例講解
這篇文章主要介紹了MySQL創(chuàng)建和刪除表操作命令實(shí)例講解,本文講解了創(chuàng)建表、創(chuàng)建臨時表、查看已經(jīng)創(chuàng)建的mysql表等內(nèi)容,需要的朋友可以參考下2014-12-12MySQL文本文件導(dǎo)入及批處理模式應(yīng)用說明
MySQL文本文件導(dǎo)入及批處理模式應(yīng)用說明,需要的朋友可以參考下。2011-09-09mysql 5.7.15 安裝配置方法圖文教程(windows)
這篇文章主要為大家詳細(xì)介紹了mysql 5.7.15 安裝配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07MySql采用GROUP_CONCAT合并多條數(shù)據(jù)顯示的方法
這篇文章主要介紹了MySql采用GROUP_CONCAT合并多條數(shù)據(jù)顯示的方法,是MySQL數(shù)據(jù)庫程序設(shè)計(jì)中常見的實(shí)用技巧,需要的朋友可以參考下2014-10-10MySQL對數(shù)據(jù)庫數(shù)據(jù)進(jìn)行復(fù)制的基本過程詳解
這篇文章主要介紹了MySQL對數(shù)據(jù)庫數(shù)據(jù)進(jìn)行復(fù)制的基本過程,解讀了Slave的一些相關(guān)配置,需要的朋友可以參考下2015-11-11