Mysql深分页的解决方案

devtools/2025/3/26 13:05:55/
        在数据量非常大的情况下,深分页查询则变得很常见,深分页会导致MySQL需要扫描大量前面的数据,从而效率低下。例如,使用LIMIT 100000, 10时,MySQL需要扫描前100000条数据才能找到第10000页的数据。

在MySQL中解决深分页问题,可通过以下5种优化方案实现:

方案一:延迟关联 (Deferred Join)

原理:先通过子查询获取主键,再关联原表获取完整数据

        通常我们直接查询分页较大的数据速率较慢,我们可以选择优先查询主键列,因为其可以通过索引查询且速度最快,然后根据获取的主键匹配对应的数据。

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)

        这种方法的原理就是我们在进行范围查询后需要记录页尾的行号,当查询以行号开始的范围数据时直接根据行号匹配,避免了扫描前面的数据。

-- 假设已知上一页最后一条记录的id为12345
SELECT * 
FROM user 
WHERE id > 12345 
ORDER BY id 
LIMIT 10;


方案三:书签分页 (Bookmark Pagination)

原理:记录上一页最后一条数据的排序字段值

-- 假设按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;


方案四:预估分页 (Approximate Pagination)

适用场景:允许误差的近似分页

        适用于数据量极大的场景,即主键也不再进行分页查询,而是通过预估得到大致行号的范围,再通过主键匹配数据行(此方案可能会有误差,需要根据场景选择)

-- 先获取预估偏移量
SELECT COUNT(*) 
FROM user 
WHERE sort_field < {target_value};-- 再使用延迟关联获取精确数据
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;


方案五:缓存优化 (Caching)

适用场景:高频访问的固定排序分页

  1. 对常用排序方式预生成分页结果
  2. 使用Redis等缓存中间结果
  3. 查询时优先读取缓存数据

性能对比(100万数据测试):

方案传统LIMIT延迟关联有序唯一键书签分页
1000页查询耗时2.3s420ms8ms12ms
内存占用

最佳实践建议:

  1. 优先使用有序唯一键分页(如自增ID),时间复杂度从O(n)降至O(1)
  2. 对高频查询的排序字段建立索引
  3. 结合业务场景选择方案:
    • 实时性要求高 → 方案二/三
    • 数据量极大 → 方案四/五
    • 允许误差 → 方案四
  4. 对超过10万条数据的分页需求,建议改用滚动加载(无限下拉)模式

http://www.ppmy.cn/devtools/170660.html

相关文章

【江协科技STM32】软件I2C协议层读写MPU6050驱动层

回顾知识点&#xff1a; 【STM32】I2C通信协议&MPU6050芯片-学习笔记-CSDN博客 接线图 整体思路 I2C初始化 软件I2C只需要用GPIO读取函数就可以&#xff0c;不用I2C库函数&#xff1b; ① 把SCL和SDA都初始化成开漏输出模式&#xff08;开漏输出不只是只能输出、也可以输…

JVM(Java虚拟机)的核心组成

1. 类加载器&#xff08;Class Loader&#xff09; 功能&#xff1a;负责将.class文件加载到内存&#xff0c;并转换为JVM可识别的数据结构。 分类&#xff1a; 启动类加载器&#xff08;Bootstrap Class Loader&#xff09;&#xff1a;加载JAVA_HOME/lib下的核心类库&#x…

在Unity(使用C#)中,internal、virtual、sealed的区别和作用。

在Unity&#xff08;使用C#&#xff09;中&#xff0c;internal、virtual、sealed 是C#语言的访问修饰符和修饰关键字。下面为你详细解释它们的区别和作用&#xff1a; 1. internal 作用&#xff1a;internal 是访问修饰符&#xff0c;它用于限制对成员或类型的访问范围。使用…

使用DeepSeek自动化申请Manus账号指南

Manus是一家专注于手势捕捉与虚拟交互的技术平台&#xff0c;而DeepSeek&#xff08;深度求索&#xff09;作为AI解决方案提供商&#xff0c;可通过其API实现自动化流程操作。本教程将演示如何利用DeepSeek的AI能力辅助完成Manus账号申请。 一、环境准备 基础工具&#xff1a; …

【Docker系列一】Docker 简介

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【设计模式】常用的设计模式详解

常用设计模式 常用设计模式介绍设计模式的分类 工厂模式工厂模式1.场景介绍案例代码 参考链接 常用设计模式介绍 设计模式的分类 创建型模式&#xff08;Creational&#xff09;&#xff1a;关注对象的实例化过程&#xff0c;包括了如何实例化对象、隐藏对象的创建细节等。常…

C++ 核心编程 ——4.9 文件操作

4.9.0 概述 程序运行时产生的数据都属于临时数据&#xff0c;一旦运行结束都被释放&#xff0c;通过文件可以将数据持久化 C中对文件操作需要包含文件流的头文件 < fstream > 文件类型文本文件文件以文本的ASCII码&#xff08;每个字符都有对应的编码&#xff09;形式存…

【Linux】从互斥原理到C++ RAII封装实践

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…