mysql深度分頁的幾種解決方案
MySQL 解決深度分頁(Deep Pagination)的核心思想是“丟掉 OFFSET,用條件定位起點(diǎn)”,從而避免大偏移量帶來的全表掃描和大量回表。常見優(yōu)化方案如下:
游標(biāo)/范圍分頁(推薦)
原理:記住上一頁最后一條記錄的主鍵(或排序列),作為下一頁的起始條件。
示例:
-- 上一頁最后一條 id = 100000 SELECT * FROM t_order WHERE id > 100000 -- 無 OFFSET ORDER BY id LIMIT 10;
- 優(yōu)點(diǎn):直接跳到100000,性能穩(wěn)定,不隨頁碼增大而衰減;千萬級數(shù)據(jù)仍可毫秒級返回。
- 缺點(diǎn):只能順序翻頁,不能隨機(jī)跳頁;需要排序列唯一且連續(xù)。
延遲關(guān)聯(lián)(JOIN 子查詢)
原理:先用覆蓋索引在子查詢里拿到主鍵,再回表取完整行,減少大 OFFSET 的回表量。
示例:
SELECT t1.*
FROM t_order t1
JOIN (SELECT id
FROM t_order
WHERE create_time > '2023-01-01'
ORDER BY create_time
LIMIT 4500000, 10) t2 ON t1.id = t2.id;- 優(yōu)點(diǎn):比直接
LIMIT 4500000,10(該方法先數(shù)4500000條數(shù)據(jù),然后丟掉,)少讀 450w 行數(shù)據(jù)。 - 注意:子查詢里的列必須被索引覆蓋,否則仍可能全表掃描。
覆蓋索引 + 子查詢定位起點(diǎn)
原理:先用覆蓋索引查出第 N 條記錄的排序列值,再用該值作為條件取后 10 條。
示例:
-- 1. 查出第 4500000 行的 create_time SELECT create_time FROM t_order ORDER BY create_time LIMIT 4500000, 1; -- 2. 用該 create_time 作為起點(diǎn) SELECT * FROM t_order WHERE create_time >= <上一步的值> ORDER BY create_time LIMIT 10;
- 優(yōu)點(diǎn):避免大 OFFSET;支持非主鍵排序。
- 注意:排序列必須有索引,否則第 1 步也會很慢。
預(yù)計算或緩存
- 靜態(tài)數(shù)據(jù)可提前算好頁碼結(jié)果,放入 Redis 或 ES,徹底避開 MySQL。
- 動態(tài)數(shù)據(jù)可用異步任務(wù)把每頁首條主鍵寫入緩存,查詢時直接
>條件。
為什么深分頁不建議用 limit offset,size
SELECT * FROM t_order LIMIT 4500000, 10;
- MySQL 仍需掃描450萬行然后扔掉,再取 10 行,耗時隨 offset 線性增長。
- 高并發(fā)下容易造成 CPU、IO、內(nèi)存暴漲,甚至 OOM。
一句話總結(jié):“深分頁不用 OFFSET,用條件(where)定位起點(diǎn)” 是所有優(yōu)化手段的核心。
到此這篇關(guān)于mysql深度分頁的幾種解決方案的文章就介紹到這了,更多相關(guān)MySQL深度分頁內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql如何將查詢結(jié)果內(nèi)容進(jìn)行轉(zhuǎn)換
文章介紹了如何在MySQL中使用CASE表達(dá)式對查詢結(jié)果進(jìn)行多分支判斷,并分享了個人經(jīng)驗,希望對大家有所幫助2025-02-02
SQL實現(xiàn)LeetCode(183.從未下單訂購的顧客)
這篇文章主要介紹了SQL實現(xiàn)LeetCode(182.從未下單訂購的顧客),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08

