首页
直播
壁纸
友链
搜索
1
微信小程序支付全链路实战:JSAPI 下单、调起支付、回调验签与退款
266 阅读
2
微信小程序云开发实战:云函数、云数据库与云存储的正确使用姿势
256 阅读
3
微信小程序自定义 tabBar 实战:custom-tab-bar 从适配到深色模式
255 阅读
4
微信小程序 Skyline 渲染引擎实战:worklet 动画从原理到落地
253 阅读
5
微信小程序分包进阶:独立分包、预下载与分包异步化实战
246 阅读
服务器运维
后端技术
前端技术
梯子
数据库
小程序
登录
搜索
标签搜索
fastadmin
Redis
微信小程序
前端开发
RabbitMQ
Go
服务器
codex
buildadmin
小程序
mysql
Nginx
Docker
Vue3
Node.js
MySQL优化
Linux
TypeScript
JWT
PHP
沿途的风景
累计撰写
74
篇文章
累计收到
0
条评论
首页
栏目
服务器运维
后端技术
前端技术
梯子
数据库
小程序
页面
直播
壁纸
友链
搜索到
1
篇与
» mysql
的结果
2026-02-27
MySQL如何解决深度分页问题?
在 MySQL 开发中,除了计数场景,深度分页(即 LIMIT offset, size 中 offset 值极大的分页查询)也是高频遇到的性能问题。比如"查询第1000页数据,每页10条"(LIMIT 9990, 10),常会出现查询缓慢的情况。下面详细讲解深度分页的问题根源及解决方案。1. 深度分页的问题根源先明确常规分页的实现方式:使用 LIMIT offset, size,其中 offset 表示跳过前 N 条数据,size 表示取 N 条数据。问题核心: 当 offset 极大时(如 9990),MySQL 需要先扫描并跳过前 9990 条数据,再取 10 条数据。即使查询条件有索引,也需要遍历索引到第 9990 条位置,才能定位到目标数据,导致 IO 开销大、查询效率低。示例(低效查询):-- 查询第1000页数据,每页10条,offset=9990 SELECT id, name FROM test_table LIMIT 9990, 10; -- 问题:MySQL需扫描前9990条数据并跳过,仅返回最后10条,资源浪费严重2. 解决方案(按适用场景排序)方案1:基于主键/索引排序+条件过滤(推荐,适用大部分场景)核心思路: 利用主键或有序索引的连续性,通过 WHERE 条件直接定位到"上一页最后一条数据",替代 offset 跳过数据。要求查询结果必须按主键或有序索引字段排序。实现步骤:分页查询时,记录上一页最后一条数据的主键/索引字段值(如最后一条数据的 id=9990);下一页查询时,通过 WHERE 主键 > 上一页最后主键 直接过滤前 9990 条数据,再用 LIMIT size 取数。示例(优化后查询):-- 第1页查询(无offset,直接取前10条) SELECT id, name FROM test_table ORDER BY id ASC LIMIT 10; -- 记录第1页最后一条数据的id=10 -- 第2页查询(通过id>10过滤前10条,无需offset) SELECT id, name FROM test_table WHERE id > 10 ORDER BY id ASC LIMIT 10; -- 记录第2页最后一条id=20 -- 第1000页查询(直接过滤前9990条,效率极高) SELECT id, name FROM test_table WHERE id > 9990 ORDER BY id ASC LIMIT 10;优点: 利用索引快速定位,无需扫描跳过的数据,查询效率稳定且高效缺点: 仅支持"下一页"查询,不支持直接跳转到任意页(如直接跳第1000页,需知道第999页最后一条的 id)方案2:游标分页(适合滚动加载场景)核心思路: MySQL 的 CURSOR(游标)本质是一个指向查询结果集的指针,可通过游标逐页读取数据,避免 offset 的低效扫描。适合"滚动加载更多"(如 APP 下拉加载)的场景,不支持跳页。实现步骤:-- 1. 声明游标(指定查询条件和排序方式) DECLARE cur_page CURSOR FOR SELECT id, name FROM test_table ORDER BY id ASC; -- 2. 打开游标 OPEN cur_page; -- 3. 读取数据(每次读取10条,即一页) FETCH cur_page INTO @id, @name; -- 逐行读取,可循环读取10条作为一页 -- 4. 关闭游标 CLOSE cur_page;优点: 适合大量数据的滚动加载,效率稳定缺点: 不支持直接跳页,语法较复杂,需在存储过程中使用方案3:预计算汇总表(适合静态/低频更新数据)核心思路: 如果数据是静态的(如历史订单、归档数据)或更新频率极低,可提前预计算分页所需的"分页标记"(如每10条数据的最大主键),存储在汇总表中。查询时直接从汇总表获取目标页的标记,再查询主表数据。实现示例:-- 1. 创建汇总表(存储每页最后一条数据的id和页码) CREATE TABLE page_summary ( page_num INT PRIMARY KEY, -- 页码 last_id INT -- 该页最后一条数据的id ); -- 2. 预插入数据(可通过定时任务更新) INSERT INTO page_summary VALUES (1, 10), (2, 20), ..., (1000, 10000); -- 3. 查询第1000页数据(先查汇总表,再查主表) SELECT last_id FROM page_summary WHERE page_num = 999; -- 得到第999页最后id=9990 SELECT id, name FROM test_table WHERE id > 9990 ORDER BY id ASC LIMIT 10;优点: 查询速度极快,适合大数据量静态数据缺点: 不适合动态更新数据,需维护汇总表(增加存储和维护成本)方案4:限制分页深度(业务层面优化)核心思路: 从业务角度限制用户的分页深度,避免用户查询过深的页码。比如"最多支持查询前100页数据",超过则提示"数据过多,请缩小查询范围"。实现示例:-- 限制offset最大值为9990(即最多100页) SELECT id, name FROM test_table WHERE offset <= 9990 LIMIT #{offset}, #{size};优点: 简单易实现,从根源减少深度分页查询缺点: 有业务局限性,不适用于必须支持深分页的场景(如后台数据导出)3. 方案选择总结方案适用场景核心优势局限性主键/索引条件过滤大部分动态数据分页(如列表查询)效率高、实现简单、兼容性好不支持直接跳页游标分页APP滚动加载、大量数据逐页读取效率稳定、适合大数据量不支持跳页、语法复杂预计算汇总表静态/低频更新数据(如归档、报表)查询速度极快需维护汇总表、不支持动态数据限制分页深度业务允许限制分页范围(如前台列表)实现简单、无性能开销业务局限性大补充提示: 深度分页优化的核心是"避免扫描跳过无关数据",无论哪种方案,都需确保查询条件中的排序字段有索引(如主键默认有索引),否则仍会出现全表扫描,优化失效。
2026年02月27日
45 阅读
0 评论
0 点赞
0:00