当前位置: 首页 > web >正文

MySQL深分页的处理方案

 一、问题根源:为什么深分页效率低?

以最常见的 MySQL LIMIT offset, size 为例:

SELECT * FROM orders ORDER BY id DESC LIMIT 10000, 20;

        (1)数据库需要先排序(ORDER BY id DESC)。

        (2)然后跳过前 10000 条记录(OFFSET 10000)。

        (3)最后返回接下来的 20 条记录。

性能瓶颈在于第 2 步:跳过(OFFSET)。
数据库服务器需要先读取、排序并临时存储 (10000 + 20) 条数据,然后丢弃前 10000 条,只返回最后 20 条。这个“跳过”的过程消耗大量的 CPU 和 I/O 资源,但绝大部分计算成果都被丢弃了,造成了巨大的浪费。


二、解决方案

针对不同的场景和数据库类型,有以下几种主流解决方案,从上手难度和效果推荐依次如下:


方案一:游标分页/查询【推荐】

        这是解决深分页最常用且高效的方案。其核心思想是:不使用固定的页码(Page),也不使用偏移量(OFFSET),而是使用上一页最后一条记录的唯一标识(如自增ID、时间戳)作为“游标”来获取下一页的数据。

实现方式:

-- 第一页
SELECT * FROM table ORDER BY id LIMIT 10;-- 第二页(假设上一页最后一条的 id 是 100)
SELECT * FROM table WHERE id > 100 ORDER BY id LIMIT 10;-- 第三页(上一页最后 id 是 200)
SELECT * FROM table WHERE id > 200 ORDER BY id LIMIT 10;

优点:
性能极高:无论翻到第几页,查询速度都只和 LIMIT size 有关,与偏移量无关。
适合无限滚动:非常适合移动端APP的无限下拉滚动场景。

缺点:
不能直接跳转到指定页码:用户只能一页一页地顺序浏览(下一页/上一页),无法直接跳到第 N 页。
要求排序字段唯一且连续:通常使用自增主键或唯一索引的时间戳。如果排序字段有大量重复值,需要结合其他字段(如主键)来确保顺序的唯一性。


方案二:覆盖索引+ 延迟关联优化

如果查询必须使用 LIMIT offset, size,可以尝试通过覆盖索引来减少回表开销。

优化后的查询:

SELECT * FROM orders 
INNER JOIN (SELECT id FROM orders ORDER BY create_time DESC LIMIT 100000, 20
) AS tmp ON orders.id = tmp.id;

        子查询 SELECT id ... 只查询了索引列 id 和 create_time,这个操作可以在覆盖索引上完成,非常快。生成一个只有 20 个 ID 的临时结果集,然后再通过 JOIN 回表查询这 20 条记录的完整数据。大大减少了回表的次数。

优点:
能在一定程度上缓解深分页问题。

缺点:
仍然是 OFFSET 方案,跳过的记录越多,子查询扫描索引的范围依然很大,只是比回表全记录要轻量很多。并非根治方案。
需要建立合适的覆盖索引。


方案三:业务层优化(禁止超深分页)

从产品设计层面限制用户的行为。

例如:
百度/谷歌搜索通常只提供最多 100 页的结果。
在移动端APP中,更常见的交互是“无限下拉滚动”而非传统的页码跳转(游标分页)。
后台系统可以限制 offset 的最大值(例如最大只能取 1000),或者当 offset 超过一个阈值(如 1000)时,提示用户“请使用更精确的筛选条件来缩小范围”。

优点:
简单粗暴,有效防止数据库被慢查询拖垮。

缺点:
是一种“限制”而非“解决”,功能上做了妥协。


方案四:使用专用搜索引擎

如果数据量极其庞大(亿级以上),且分页查询需求复杂(带多种过滤和排序),传统的 RDBMS 会非常吃力。此时应考虑将数据同步到专用的搜索引擎中,如:

Elasticsearch:天然支持深分页,提供了 search_after 参数来实现类似游标分页的功能,比 from + size 的方式高效得多。

优点:
能处理海量数据的复杂查询和分页。

缺点:
架构复杂,需要引入和维护新的中间件,有数据同步延迟。

http://www.xdnf.cn/news/18685.html

相关文章:

  • React学习(十一)
  • 深入理解 React useEffect
  • 三、Bpmnjs 核心组件与架构介绍
  • 【c++进阶系列】:万字详解多态
  • 分库分表系列-基础内容
  • piecewise jerk算法介绍
  • 密码实现安全基础篇 . KAT(已知答案测试)技术解析与实践
  • SpringBoot自动配置原理解析
  • Reactor 反应堆模式
  • 游游的数组询问
  • SOC估算方法-蜣螂优化算法结合极限学习
  • NVIDIA Nsight Systems性能分析工具
  • 【Linux系统】进程信号:信号的处理
  • 【基础-判断】订阅dataReceiveProgress响应事件是用来接收HTTP流式响应数据。
  • 基于LLM的跨架构物联网静态漏洞挖掘检测 摘要
  • Ubuntu2204server系统安装postgresql14并配置密码远程连接
  • 小程序备案话术
  • 关于微服务下的不同服务之间配置不能通用的问题
  • pid自适应调节实战设计-基于输出电流的PI参数切换方案
  • React Hooks原理深潜:从「黑魔法」到「可观测」的蜕变之旅
  • Linux服务器Systemctl命令详细使用指南
  • DeepSeek V3.1 横空出世:重新定义大语言模型的边界与可能
  • 水体反光 + 遮挡难题破解!陌讯多模态融合算法在智慧水务的实测优化
  • 深入理解纹理与QtOpenGL的实现
  • 深度集成Dify API:基于Vue 3的智能对话前端解决方案
  • GitHub 热榜项目 - 日榜(2025-08-23)
  • Git的下载安装和使用以及和IDEA的关联
  • 微服务概述1
  • 【K8s】微服务
  • Claude Code快捷键介绍(Claude Code命令、Claude Code指令、Claude Code /命令、Claude命令、Claude指令)