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

详解Mysql解决深分页方案

        MySQL 解决深分页(如 LIMIT 1000000, 10)的核心思路是 避免扫描和丢弃大量无用数据

一、问题本质:为什么深分页慢?

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

执行过程

  • 扫描前 1,000,010 行

  • 丢弃前 1,000,000 行

  • 返回最后 10 行

 代价:O(N) 复杂度,百万级数据需 1-10 秒

二、七大解决方案

方案 1:游标分页(最优解)

原理:记录上一页最后一条记录的 ID,直接定位起点

-- 第一页(常规)
SELECT * FROM orders ORDER BY id DESC LIMIT 10;-- 下一页(核心!)
SELECT * FROM orders 
WHERE id < 上一页最后ID  -- 直接跳过已读数据
ORDER BY id DESC 
LIMIT 10;

优点

  •  时间复杂度 O(10) → 恒定为 10 行扫描

  •  支持顺序/倒序翻页

  •  数据一致性高(无新增删除时)

限制

  • 只能顺序翻页,不能跳页

  • 需前端传递最后一条记录的 ID

方案 2:延迟关联(覆盖索引优化)

原理:先通过索引定位 ID,再回表取数据

SELECT * FROM orders
INNER JOIN (SELECT id FROM orders      -- 只查索引ORDER BY create_timeLIMIT 1000000, 10
) AS tmp USING(id);            -- 回表取完整数据

优势

  • 子查询仅扫描索引(体积小)

  • 减少 90% 以上的回表量

  • 尤其适合 ORDER BY 非主键列的场景

性能对比

原查询延迟关联
扫描 1,000,010 行数据扫描 1,000,010 行索引
1,000,010 次回表仅 10 次回表

方案 3:范围分页(ID 分段)

原理:用 WHERE 替代 OFFSET

SELECT * FROM orders
WHERE id BETWEEN 1000000 AND 1000010;  -- 精确范围

适用场景

  • 主键连续且无删除

  • 已知分页边界值(如每页固定 1000 条)

方案 4:业务降级(近似分页)

策略

  • 限制深度:WHERE page_no <= 100(禁止查 100 页后)

  • 模糊跳页:只提供「上一页/下一页」,不显示总页数

  • 滚动加载:用 JS 实现无限滚动,避免传统分页

方案 5:预计算分页(空间换时间)

步骤

  • 创建分页映射表:

    CREATE TABLE page_index (page INT PRIMARY KEY,min_id INT,max_id INT
    );
  • 定期更新分页范围

  • 查询时直接定位:

    SELECT * FROM orders
    WHERE id BETWEEN (SELECT min_id FROM page_index WHERE page=100)AND (SELECT max_id FROM page_index WHERE page=100);

 方案 6:专用搜索引擎

工具选择

  • Elasticsearch:search_after API 支持深度游标

  • ClickHouse:内置分页优化引擎

  • TiDB:分布式数据库线性扩展

方案 7:分区表(MySQL 8.0+)

利用分区裁剪

-- 按范围分区
CREATE TABLE orders (id INT AUTO_INCREMENT,...PRIMARY KEY(id)
) PARTITION BY RANGE(id) (PARTITION p0 VALUES LESS THAN (100000),PARTITION p1 VALUES LESS THAN (200000),...
);-- 查询时自动过滤无关分区
SELECT * FROM orders
WHERE id > 1000000
ORDER BY id LIMIT 10;

 三、方案选择决策树

 四、性能对比测试(1000万行数据)

方案页数耗时扫描行数
原始 LIMIT第50万页4.2s5,000,010
延迟关联第50万页0.8s5,000,010*
游标分页第50万页0.003s10
Elasticsearch第50万页0.15s10

*:延迟关联仅索引扫描,成本远低于数据扫描

五、终极建议

  • 首选游标分页:99% 的场景适用,需前后端配合

  • 次选延迟关联:兼容传统分页 API

  • 禁用 OFFSET:在代码规范中明确禁止 offset > 10000

  • 监控慢查询:捕获深分页 SQL

    -- 查找可疑深分页
    SELECT * FROM sys.slow_log
    WHERE sql_text LIKE '%LIMIT%,%';

http://www.dtcms.com/a/289630.html

相关文章:

  • 试用SAP BTP 05A:AI服务-Document Information Extraction
  • Python桌面版数独(二版)-增加4X4、6X6
  • 小型支付项目3-5:检测未接收到或未正确处理的支付回调通知
  • 论文笔记:Seed: Bridging Sequence and Diffusion Models for RoadTrajectory Generation
  • LLM指纹底层技术——KV缓存压缩
  • 嵌入式通信DQ单总线协议及UART(一)
  • 是否可以将“进化”应用到软件系统的设计中?
  • 049_List接口(ArrayList / LinkedList / Vector)
  • Three.js + WebGL 深空星波粒子动画特效制作详解
  • 30天打牢数模基础-模拟退火算法讲解
  • 零基础100天CNN实战计划:用Python从入门到图像识别高手
  • k8s:离线添加集群节点
  • Java中的ScopeValue 使用详解
  • 深入解析业务代表模式:解耦表示层与业务层的利器
  • 列空间与零空间,秩—零化度定理
  • ( LeetCode 面试经典 150 题 ) 202. 快乐数 (快慢指针)
  • [simdjson] `error_code` | .get() | 异常 | is_fatal() | current_location() | 链式处理
  • 限流算法与实现
  • MySQL锁(一) 概述与分类
  • CMSIS-RTOS线程创建osThreadNew
  • JAVA国际版任务悬赏+接单系统源码支持IOS+Android+H5
  • 代码随想录算法训练营二十一天|回溯part03
  • IDEA使用技巧
  • c/c++-memory-management
  • ansible awx自动化工具学习准备
  • 牛客-两个链表的第一个公共节点
  • 安全信息与事件管理(SIEM)系统架构设计
  • TypeScript 中替代 Interface 的方案
  • PLC(可编程逻辑控制器,Programmable Logic Controller)是什么?
  • 详解如何解决Mysql主从复制延迟