当前位置: 首页 > 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.xdnf.cn/news/1155997.html

相关文章:

  • Python类中方法种类与修饰符详解:从基础到实战
  • [simdjson] ondemand::value | object array
  • 低速信号设计之I3C篇
  • 嵌入式Linux:获取线程ID
  • gym 安装
  • PrimeTime:高级片上变化(AOCV)
  • Laravel 框架NOAUTH Authentication required 错误解决方案-优雅草卓伊凡
  • 分享如何在保证画质的前提下缩小视频体积实用方案
  • NISP-PTE基础实操——XSS
  • MybatisPlus-14.扩展功能-DB静态工具-练习
  • windows + phpstorm 2024 + phpstudy 8 + php7.3 + thinkphp6 配置xdebug调试
  • MySQL学习----Explain
  • Kubernetes (K8S)知识详解
  • 二阶 IIR(biquad)滤波器
  • 红宝书单词学习笔记 list 51-75
  • Product Hunt 每日热榜 | 2025-07-20
  • 【c++】200*200 01灰度矩阵求所有的连通区域坐标集合
  • 去中心化协作智能生态系统
  • RK3588 安卓adb操作
  • Order Capital Round 1 (Codeforces Round 1038, Div. 1 + Div. 2) C、D
  • 讲解Mysql OnlineDDL的算法
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘lxml’问题
  • docker Neo4j
  • 【RK3576】【Android14】显示屏MIPI开发调试
  • 【图文详解】Transformer架构详细解析:多头自注意力机制、qkv计算过程、encoder架构、decoder架构以及mask的意义
  • Qwen3-8B 与 ChatGPT-4o Mini 的 TTFT 性能对比与底层原理详解
  • 网鼎杯2020青龙组notes复现
  • springboot websocket 自动重启方案
  • 彩虹云商城全源码 - 全新客服系统上线
  • CAN通讯理论与实践:调试和优化全讲解