Mysql中深分页的五种常用方法整理

2025-03-25 15:50

本文主要是介绍Mysql中深分页的五种常用方法整理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Mysql中深分页的五种常用方法整理》在数据量非常大的情况下,深分页查询则变得很常见,这篇文章为大家整理了5个常用的方法,文中的示例代码讲解详细,大家可以根据自己的需求进行选择...

在数据量非常大的情况下,深分页查询则变得很常见,深分页会导致mysql需要扫描大量前面的数据,从而效率低下。例如,使用LIMIT 100000, 10时,MySQL需要扫描前100000条数据才能找到第10000页的数据。
在MySQL中解决深分页问题,可通过以下5种优化方案实现:

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

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

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

SELECT t.* 
FROM user t
INNER JOIN (
SELECT id 
FROM user 
OwdjzdXRDER 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 < {thttp://www.chinasem.cnarget_value} 
ORDER BY sort_field 
LIMIT 10
) AS tmp ON t.id = tmp.id;

方案五:缓存优化 (Caching)

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

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

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

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

最佳实践建议

1.优先使用有序唯一键分页(如自增ID),时间复杂度从O(n)降至O(1)

2.对高频查询的排序字段建立索引

3.结合业务场景选择方案:

  • 实时性要求高 → 方案二/三
  • 数据量极大 → 方案四/五
  • 允许误差 → 方案四

4.对超过10万条数据的分页需求,建议改用滚动加载(无限下拉)模式

方法补充

下面小编为大家整理了一些Mysql深度分页优化的其他思路和方案,希望对大家有所帮助

1.普通分页的优化方法

一般分页不是很深的情况下,我们一般可以通过以下方法解决大部分的分页问题

通过增加主键排序,例如:order by id

如果需要根据时间排序,就给常用的字段增加索引,包括时间字段。例如:order by create_time

以上两种手段其实可以解决大部分的分页问题了。但是如果后面的页数很深了,比如从100w条开始取20条,我们就会发现再执行sql语句就会非常慢,这是因为mysql的优化器在发现sql查询的行数php超过一定比例的时候,就会自动转换成全表扫描,可以自己模拟数据测试一下。

什么是Mysql的深度分页?

查询偏移量过大的分页的场景我们称为深度分页,例如以下sql语句就是一个典型的深度分页场景

SELECT * FROM t_xxx ORDER BY id LIMIT 1000000, 20

2.深度分页的优化方案

强制索引 force index(不推荐)

一开始想着使用force index强制走索引,但是我的leader跟我说过,不建议添加强制索引来进行sql优化,主要有以下几种缺点:

  • 影响选择性最佳的索引:强制使用索引可能会影响数据库引擎选择性最佳的索引,导致查询性能下降
  • 增加更新操作的时间:强制使用索引后,数据库更新操作的时间会增加,因为索引文件需要被更新
  • 降低查询的灵活性:如果强制使用索引过于固定,会降低查询的灵活性,不方便后期维护。

ID范围查询

如果那种不需要页码的场景下,比如滑动加载(消息列表这种),还有那种只有上下页按钮点击的网站分页,我们可以通过where id > #{上次查询的最后一条记录的id} 进行优化

# 查询指定 ID 范围的数据
SELECT * FROM t_xxx WHERE id > 1000000 AND id <= 1000020 ORDER BY id
# 也可以通过记录上次查询结果的最后一条记录的ID进行下一页的查询
SELECT * FROM t_xxx WHERE id > 1000000 LIMIT 20

子查询+INNER JOIN

可以先根据时间字段(create_time)或者id排序查询到id,比如:

SELECT id FROM t_xxx ORDER BY create_time DESC LIMIT 1000000,20

这个子查询先查出来,作为临时表,然后再让主表join这个临时表去联表查询需要的t_xxx对应的信息字段,这样也可以达到一个很好的效果,最终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过滤优化的方式进行优化,例如:

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

到此这篇关于Mysql中深分页的五种常用方法整理的文章就介绍到这了,更多相关Mysql深分页内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多http://www.chinasem.cn支持编程China编程(www.chinasem.cn)!

这篇关于Mysql中深分页的五种常用方法整理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153927

相关文章

检查 Nginx 是否启动的几种方法

《检查Nginx是否启动的几种方法》本文主要介绍了检查Nginx是否启动的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1. 使用 systemctl 命令(推荐)2. 使用 service 命令3. 检查进程是否存在4

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

MySQL字符串转数值的方法全解析

《MySQL字符串转数值的方法全解析》在MySQL开发中,字符串与数值的转换是高频操作,本文从隐式转换原理、显式转换方法、典型场景案例、风险防控四个维度系统梳理,助您精准掌握这一核心技能,需要的朋友可... 目录一、隐式转换:自动但需警惕的&ld编程quo;双刃剑”二、显式转换:三大核心方法详解三、典型场景

MySQL中between and的基本用法、范围查询示例详解

《MySQL中betweenand的基本用法、范围查询示例详解》BETWEENAND操作符在MySQL中用于选择在两个值之间的数据,包括边界值,它支持数值和日期类型,示例展示了如何使用BETWEEN... 目录一、between and语法二、使用示例2.1、betwphpeen and数值查询2.2、be

MySQL快速复制一张表的四种核心方法(包括表结构和数据)

《MySQL快速复制一张表的四种核心方法(包括表结构和数据)》本文详细介绍了四种复制MySQL表(结构+数据)的方法,并对每种方法进行了对比分析,适用于不同场景和数据量的复制需求,特别是针对超大表(1... 目录一、mysql 复制表(结构+数据)的 4 种核心方法(面试结构化回答)方法 1:CREATE

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

springboot中配置logback-spring.xml的方法

《springboot中配置logback-spring.xml的方法》文章介绍了如何在SpringBoot项目中配置logback-spring.xml文件来进行日志管理,包括如何定义日志输出方式、... 目录一、在src/main/resources目录下,也就是在classpath路径下创建logba

SQL Server中行转列方法详细讲解

《SQLServer中行转列方法详细讲解》SQL行转列、列转行可以帮助我们更方便地处理数据,生成需要的报表和结果集,:本文主要介绍SQLServer中行转列方法的相关资料,需要的朋友可以参考下... 目录前言一、为什么需要行转列二、行转列的基本概念三、使用PIVOT运算符进行行转列1.创建示例数据表并插入数

MyBatis配置文件中最常用的设置

《MyBatis配置文件中最常用的设置》文章主要介绍了MyBatis配置的优化方法,包括引用外部的properties配置文件、配置外置以实现环境解耦、配置文件中最常用的6个核心设置以及三种常用的Ma... 目录MyBATis配置优化mybatis的配置中引用外部的propertis配置文件⚠️ 注意事项X

C++打印 vector的几种方法小结

《C++打印vector的几种方法小结》本文介绍了C++中遍历vector的几种方法,包括使用迭代器、auto关键字、typedef、计数器以及C++11引入的范围基础循环,具有一定的参考价值,感兴... 目录1. 使用迭代器2. 使用 auto (C++11) / typedef / type alias