MySQLLIMIT深分页性能问题与优化实战

来源:这里教程网 时间:2026-02-12 11:19:07 作者:
一、题目回顾二、MySQL 的执行逻辑三、代入具体数字四、更大的偏移量时的问题五、为什么 MySQL 要这么干?六、如何优化深分页?方法 1:基于主键或排序字段“范围分页”方法 2:记录上次分页的“游标位置”方法 3:子查询 + JOIN 减少数据传递量(部分场景)七、结论总结八、总结

一、题目回顾

执行语句如下:

SELECT * FROM orders LIMIT 100, 100;

意思是:
跳过前 100 行,取接下来的 100 行。

二、MySQL 的执行逻辑

MySQL 的 LIMIT offset, count 实际执行流程是这样的:

    从结果集的开头开始扫描;一直取到 offset + count 条;扔掉前 offset 条;返回后面的 count 条给客户端。

???? 换句话说:

MySQL 必须先扫描 offset + count 行数据, 再丢弃 offset 行,只返回 count 行。

三、代入具体数字

你的 SQL:

LIMIT 100, 100

即:

offset = 100count = 100

那么 MySQL 实际上会扫描 200 行

扫描 200 行 → 丢掉前 100 行 → 返回 100 行。

四、更大的偏移量时的问题

假设语句:

SELECT * FROM orders LIMIT 1000000, 100;

MySQL 依然会:

扫描前 1,000,100 行丢掉前 1,000,000 行;仅返回最后的 100 行。

⚠️ 性能问题:

offset 越大,浪费越多;MySQL 没有“从第 N 条开始读取”的索引级跳转机制;所以分页越深,查询越慢。

五、为什么 MySQL 要这么干?

MySQL 的执行计划是基于结果集顺序的:

没有 offset 索引直接跳过功能;除非你手动提供一个有序字段(如自增 id 或时间戳);否则它必须遍历前 offset 行,才能保证返回结果的排序正确。

六、如何优化深分页?

方法 1:基于主键或排序字段“范围分页”

例如原语句:

SELECT * FROM orders ORDER BY id LIMIT 1000000, 100;

可以改为:

SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 100;

这样 MySQL 可以用索引定位到 id=1000001 的位置,然后顺序扫描 100 行,性能极快。

方法 2:记录上次分页的“游标位置”

前端分页时保存最后一条记录的 ID:

-- 第一次查询 SELECT * FROM orders ORDER BY id LIMIT 100; -- 第二页查询 SELECT * FROM orders WHERE id > {last_id_of_prev_page} ORDER BY id LIMIT 100;

这叫 Keyset Pagination(基于键的分页)
可以避免深度偏移,尤其适合滚动加载、无限下拉列表等场景。

方法 3:子查询 + JOIN 减少数据传递量(部分场景)

SELECT o.* FROM orders o JOIN ( SELECT id FROM orders ORDER BY id LIMIT 1000000, 100 ) t ON o.id = t.id; 子查询只拿 ID(轻量);再 JOIN 原表获取完整行;比直接 LIMIT 效率更好。

七、结论总结

语句实际扫描行数返回行数特点LIMIT 100, 100200 行100 行小偏移量,影响可忽略LIMIT 1000000, 1001,000,100 行100 行⚠️ 深分页,极慢WHERE id > x LIMIT 100100 行100 行✅ 推荐分页方式

八、总结

MySQL 的 LIMIT offset, count 会扫描 offset + count 行,返回 count 行。
当 offset 很大时,性能急剧下降,建议用基于主键的范围分页(Keyset Pagination) 代替。

到此这篇关于MySQL LIMIT 深分页性能问题与优化实战的文章就介绍到这了,

相关推荐

热文推荐