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

MySQL 深分页优化与条件分页:把 OFFSET 换成“游标”,再用覆盖索引抄近路

MySQL 深分页优化与条件分页:把 OFFSET 换成“游标”,再用覆盖索引抄近路

这不是“玄学调优”,而是可复制的方案。本文用可复现的 DDL/造数脚本,演示为什么 OFFSET 越大越慢,如何用 条件游标(Keyset Pagination) 替换它,并配上 覆盖索引。还会教你看 EXPLAIN/EXPLAIN ANALYZE 与慢日志,拿到优化前后的硬指标。

文章目录

  • MySQL 深分页优化与条件分页:把 OFFSET 换成“游标”,再用覆盖索引抄近路
    • @[toc]
    • 0. TL;DR(先给答案)
    • 1. 可复现环境(DDL/造数)
    • 2. 为什么深分页用 OFFSET 会慢?
    • 3. 条件游标(Keyset Pagination):用边界替代偏移
      • 3.1 基本写法(全站时间线)
      • 3.2 用户页/筛选页
      • 3.3 稳定性与并发插入
    • 4. 覆盖索引:一页信息“在索引里就够了”
    • 5. 联表场景的分页套路
      • 5.1 先定位 id,再回表取详情
      • 5.2 标签/多条件
    • 6. Explain 前后对比:怎么看才算“快了”
    • 7. 开慢日志 & 抓“优化前/后”的证据
    • 8. API 接口如何落地(游标凭证)
    • 9. 边界与常见坑
    • 10. 一页就抄的“覆盖索引清单”
    • 11. 演示 SQL(复制即可跑)
    • 12. 收尾

0. TL;DR(先给答案)

  • 深分页不要 OFFSETLIMIT 20 OFFSET 100000 会让 InnoDB 扫描并丢弃前 10 万行。
  • 条件游标:按稳定排序键(如 created_at, id)记住“上一页最后一条”的边界,下一页用
    WHERE (created_at,id) < (?,?) ORDER BY created_at DESC, id DESC LIMIT 20
  • 覆盖索引:如果一页只展示 id/created_at/total,就建立 (created_at DESC, id DESC, total) 组合索引,查询即走 Index Only Scan,无需回表。
  • 监控与验证:EXPLAIN ANALYZE 看“rows examined/loops/时间”,开启慢日志看是否还在爆。

1. 可复现环境(DDL/造数)

直接在 MySQL 8.0+ 执行;数据量不大也能看出差距,想更明显把 N_ORDERS 调大。

CREATE DATABASE IF NOT EXISTS demo;
USE demo;DROP TABLE IF EXISTS orders;
CREATE TABLE orders (id BIGINT PRIMARY KEY AUTO_INCREMENT,user_id BIGINT NOT NULL,status ENUM('CREATED','PAID','CANCELLED') NOT NULL,total_cents INT NOT NULL,created_at DATETIME NOT NULL,KEY idx_ctime_id (created_at DESC, id DESC),                 -- 全局时间倒序翻页KEY idx_user_ctime_id (user_id, created_at DESC, id DESC),   -- 用户维度翻页KEY idx_status_ctime (status, created_at DESC)               -- 常见过滤
) ENGINE=InnoDB;-- 造 20 万行(递归 CTE)
WITH RECURSIVE seq AS (SELECT 1 AS nUNION ALLSELECT n+1 FROM seq WHERE n < 200000
)
INSERT INTO orders (user_id, status, total_cents, created_at)
SELECT1 + FLOOR(RAND()*5000)  AS user_id,ELT(1+FLOOR(RAND()*
http://www.dtcms.com/a/335121.html

相关文章:

  • WSL 配置文件 wsl.conf 设置
  • IOMMU的2级地址翻译机制及多级(2~5)页表查找
  • 56. 合并区间
  • 计算你的身体质量指数(BMI)
  • SQL183 近三个月未完成试卷数为0的用户完成情况
  • ​江湖四大秘本之一的《英耀篇》​
  • 片料矫平机科普
  • Spring AI架构分析
  • leetcode-139. 单词拆分-C
  • 每日任务day0816:小小勇者成长记之符文羊皮卷
  • Java -- 泛型-自定义泛型
  • 【数据结构入门】二叉树(2)
  • 数据结构 实现循环队列的三种方法
  • 模式组合应用-桥接模式(一)
  • (论文速读)ViDAR:视觉自动驾驶预训练框架
  • Harmony OS 开发入门 第四章
  • C# 反射和特性(关于应用特性的更多内容)
  • 022 基础 IO —— 文件
  • 服务器硬件电路设计之I2C问答(七):解析 I2C 通信 “卡壳” 难题:从设备无响应与跨电压兼容之道
  • Apache Hudi:数据湖的实时革命
  • 【每日一题】Day5
  • 一键检测接口是否存活:用 Python/Shell 写个轻量级监控脚本
  • 后量子密码算法ML-KEM介绍及开源代码实现
  • 数据结构:二叉平衡树
  • ROS move_base 混合功能导航 RealSense D435i + 3D 点云地图 + 楼层切换 + 路径录制 + 路径规划
  • 微服务的编程测评系统12-xxl-job-历史竞赛-竞赛报名
  • C++ 力扣 1658.将 x 减到 0 的最小操作数 题解 优选算法 滑动窗口 (同向双指针)优化 每日一题 详细题解
  • 免费万能电子书格式转换器!Neat Converter支持 ePub、Azw3、Mobi、Doc、PDF、TXT 文件的相互转换。
  • 两个简单的设计模式的例子
  • FP16(半精度)和FP32(单精度)