MySQL的深度分页如何优化!

MySQL深度分页(例如 LIMIT 1000000, 20)性能差的主要原因在于 OFFSET 需要扫描并跳过大量数据,即使这些数据最终并不返回。随着 OFFSET 增大,性能会急剧下降。

以下是优化深度分页的常用策略,根据场景选择最适合的方案:

🛠 1. 使用覆盖索引 + 延迟关联 (最常用且有效)

  • 核心思想:
    • 先利用覆盖索引快速找到目标分页行的主键(避免回表)。
    • 再根据这些主键回表关联获取完整的行数据。
  • 优化前 (性能差):
    SELECT * FROM your_table ORDER BY sort_column LIMIT 1000000, 20;
    
  • 优化后:
    SELECT t.*
    FROM your_table t
    JOIN (SELECT id -- 只选择主键FROM your_tableORDER BY sort_column -- 确保有 (sort_column, id) 或类似索引LIMIT 1000000, 20
    ) AS tmp ON t.id = tmp.id; -- 通过主键关联回原表
    
  • 为什么有效:
    • 子查询 SELECT id ... LIMIT 1000000, 20 利用了覆盖索引(仅包含 sort_columnid 的索引)。数据库引擎只需扫描索引结构就能找到这 20 行的 ID,速度非常快(索引通常比表数据小得多,且在内存中可能性高)。
    • 外层查询 SELECT t.* ... 只需要精确地根据这 20 个 ID 回表查询完整数据,效率极高。
  • 关键:
    • 必须创建合适的索引: 通常是 (sort_column, id)(sort_column, other_columns_in_where)。确保子查询能够使用覆盖索引。如果 sort_column 本身是主键或唯一索引,直接用 (sort_column) 即可。
    • 适用于排序字段相对稳定的情况。

🔍 2. 基于游标/连续分页 (Cursor-based Pagination / Keyset Pagination)

  • 核心思想: 放弃使用 OFFSET,改为记住上一页最后一条记录的排序字段值(或多个字段值),作为下一页的起始点。
  • 优化前:
    -- Page 1
    SELECT * FROM orders ORDER BY created_at DESC, id DESC LIMIT 20;
    -- Page 2 (慢!)
    SELECT * FROM orders ORDER BY created_at DESC, id DESC LIMIT 20 OFFSET 20;
    
  • 优化后:
    -- Page 1
    SELECT * FROM orders ORDER BY created_at DESC, id DESC LIMIT 20;
    -- 假设最后一条记录: created_at = '2023-10-25 14:30:00', id = 12345
    -- Page 2 (快!)
    SELECT * FROM orders
    WHERE (created_at < '2023-10-25 14:30:00') OR(created_at = '2023-10-25 14:30:00' AND id < 12345)
    ORDER BY created_at DESC, id DESC
    LIMIT 20;
    
  • 为什么有效:
    • 完全避免了 OFFSET 的扫描跳过操作。
    • 查询利用了 (created_at DESC, id DESC) 索引进行高效的范围查找,只扫描需要的行。
  • 关键:
    • 需要一个唯一且稳定的排序键: 通常使用时间戳(如 created_at)或自增主键(如 id),或者它们的组合(如上例,防止 created_at 重复时顺序不确定)。
    • 适用于连续浏览场景: 如无限滚动、上一页/下一页导航。不支持直接跳转到任意页码
    • 需要客户端存储"游标"(即上一页最后记录的排序键值)。
    • 处理新增/删除数据时顺序变化相对稳定(取决于排序键)。

📊 3. 预先计算 & 物化视图 (Precomputation & Materialized Views)

  • 核心思想: 对于复杂查询或聚合分页,将结果预先计算并存储在一个专门的分页表或物化视图中。
  • 实现:
    • 创建一个新表,包含原始表的主键、排序字段、以及其他分页需要的聚合/计算字段。
    • 使用定时任务(Cron, Event Scheduler)或触发器(谨慎使用,性能开销大)或变更数据捕获(CDC)来维护这个表。
    • 对这个新表进行分页查询(可以使用延迟关联或游标)。
  • 为什么有效:
    • 将复杂查询的开销分摊到预计算阶段。
    • 分页查询的目标表更小、结构更简单、索引更优化。
  • 适用场景:
    • 报表分页、需要复杂聚合的分页、数据相对静态或可以接受一定延迟的场景。
    • 不适合需要实时最新数据的场景。

🔄 4. 分区 (Partitioning)

  • 核心思想: 将大表物理分割成更小的、更易管理的片段(分区)。分页查询可以限定在特定分区内进行。
  • 实现:
    • 按范围(如 created_at 年份、月份)或列表(如 region)分区。
    • 在查询中显式指定分区或利用分区剪裁(WHERE 条件匹配分区键)。
    -- 假设按年份分区
    SELECT * FROM your_table PARTITION (p2023)
    ORDER BY sort_column
    LIMIT 1000000, 20; -- 即使有 OFFSET, 但扫描的数据量仅限 2023 分区
    
  • 为什么有效:
    • 显著减少单次查询需要扫描的数据量(从全表扫描变为分区扫描)。
  • 关键:
    • 分区键的选择至关重要,必须与分页查询的 WHERE 条件或排序强相关才能有效剪裁。
    • 分区本身不能解决分区内深度分页的 OFFSET 问题,分区内数据量过大时仍需结合延迟关联或游标。
    • 分区管理和维护有额外开销。

⚙️ 5. 其他考虑与权衡

  • 避免 SELECT *: 只查询需要的列,减少数据传输和内存占用。
  • 优化 WHERE 条件: 尽可能缩小初始数据集。有效的 WHERE 条件是所有优化的基础。
  • 前端/产品设计:
    • 限制可访问的页数(例如,只允许访问前 100 页)。
    • 鼓励使用搜索/过滤缩小结果集,而不是无限制翻页。
    • 对于"跳转到最后一页"这种需求,考虑显示总条目数并提供输入框跳转,但实现时可能需要估算或缓存总数。
  • 分库分表 (Sharding): 终极方案,当单机容量和性能达到极限时。将数据分散到多个物理数据库/表中。分页查询会变得非常复杂,通常需要中间件或应用层聚合。
  • 缓存: 对特定查询模式(如热门的前几页)进行结果缓存。

📌 总结建议

  1. 首选尝试延迟关联 (覆盖索引): 适用于大多数场景,对应用层改动较小,效果显著。关键是创建正确的覆盖索引。
  2. 对于连续浏览场景 (无限滚动/上下一页): 强烈推荐游标分页: 性能最优,无 OFFSET 瓶颈。需要应用层配合存储游标。
  3. 复杂聚合/报表分页: 考虑预计算/物化视图: 将计算压力转移到后台。
  4. 海量数据且访问模式可分区: 结合分区 + 上述技巧 (延迟关联/游标): 减少单次扫描范围。
  5. 审视需求: 是否真的需要深度随机跳页?优化产品设计往往是性价比最高的方案。
  6. 监控与分析: 使用 EXPLAIN 分析查询执行计划,确认是否使用了预期的索引。

选择哪种方案取决于你的具体数据量、访问模式、排序需求、实时性要求以及对应用层改动的接受程度。通常 延迟关联游标分页 是解决深度分页性能问题最直接有效的武器💪。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/87515.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87515.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

K8s Pod 调度基础——1

目录 一、Replication Controller&ReplicaSet ‌一、Replication Controller (RC)‌ ‌原理‌ ‌特性‌ ‌意义‌ ‌示例与逐行解释‌ ‌二、ReplicaSet (RS)‌ ‌原理‌ ‌特性‌ ‌意义‌ ‌示例与逐行解释‌ ‌三、RC 与 RS 的对比‌ ‌四、总结‌ 二、Dea…

C# Task异步的常用方法

Task异步的常用方法 C# 中的 Task 类是 System.Threading.Tasks 命名空间的一部分&#xff0c;用于表示异步操作。 一、Task.Run(Action action): 此静态方法用于在后台运行一个新任务&#xff0c;并返回与该任务关联的 Task 实例。 本质是将任务放入线程池执行&#xff0c;自…

OpenResty实战之PB级物联网数据处理:时序数据库优化实战

某智慧能源平台通过本方案成功处理了日均1.2万亿数据点&#xff0c;存储成本降低70%&#xff0c;查询延迟从分钟级优化到亚秒级。本文将深入解析PB级物联网数据处理的核心挑战与时序数据库深度优化技巧。 一、物联网数据特性与存储挑战 1.1 物联网数据核心特征 #mermaid-svg-U…

聊聊架构(5)数字化时代的平台商业架构

在数字化浪潮的推动下&#xff0c;平台经济已成为全球经济增长的关键驱动力。作为架构师&#xff0c;不仅要精通架构设计的基础方法论&#xff0c;还需具备敏锐的商业洞察力。架构的价值在于服务业务和商业&#xff0c;而业务的发展又促使架构不断演进。本文将深入探讨平台的商…

【数据增强】精细化贴图数据增强

1.任务背景 假设我有100个苹果的照片&#xff0c;我需要把这些照片粘贴到传送带照片上&#xff0c;模拟“传送带苹果检测”场景。 这种贴图的方式更加合理一些&#xff0c;因为yolo之类的mosaic贴图&#xff0c;会把图像弄的非常支离破碎。 现在我需要随机选择几张苹果图像&am…

HTML响应式Web设计

什么是响应式Web设计&#xff1f; RWD指的是响应式Web设计&#xff08;Responsive Web Design)RWD能够以可变尺寸传递网页RWD对于平板和移动设备是必需的 创建一个响应式设计&#xff1a; <!DOCTYPE html> <html lang"en-US"> <head> <styl…

【读代码】百度开源大模型:ERNIE项目解析

一、项目基本介绍 1.1 项目概述 ERNIE(Enhanced Representation through kNowledge IntEgration)是百度基于PaddlePaddle深度学习框架开发的多模态预训练模型体系。最新发布的ERNIE 4.5系列包含10个不同变体,涵盖从300B参数的巨型MoE模型到0.3B的轻量级模型,形成完整的多…

2025年6月:技术探索与生活平衡的协奏曲

> 当代码与晨跑轨迹在初夏的阳光下交织,我找到了程序员生活的黄金分割点 --- ### 一、技术突破:AI驱动的智能工作流优化系统 这个月我成功部署了第三代自动化工作流系统,核心创新在于**动态决策树+实时反馈机制**。系统可自主优化处理路径,错误率下降62%! ```pyth…

如何查看服务器运行了哪些服务?

&#x1f7e2; 一、Linux服务器Linux下&#xff0c;常用以下几种方法&#xff1a;✅ 1. 查看所有正在监听端口的服务netstat -tulnp 含义&#xff1a;-t TCP-u UDP-l 监听状态-n 显示端口号-p 显示进程号和程序名示例输出&#xff1a;pgsql复制编辑Proto Recv-Q Send-Q Local A…

【Linux基础知识系列】第三十八篇 - 打印系统与 PDF 工具

在Linux系统中&#xff0c;打印和PDF处理是日常办公和文档管理中不可或缺的功能。CUPS&#xff08;Common Unix Printing System&#xff09;是Linux中常用的打印服务&#xff0c;它提供了打印任务的管理和打印设备的配置功能。同时&#xff0c;Linux也提供了多种PDF处理工具&a…

STM32CUBEMX 使用教程6 — TIM 定时器配置、定时中断

往期文章推荐&#xff1a; STM32CUBEMX 使用教程5 — DMA配置 & 串口结合DMA实现数据搬运 STM32CUBEMX 使用教程4 — 串口 (USART) 配置、重定向 printf 输出 STM32CUBEMX 使用教程3 — 外部中断&#xff08;EXTI&#xff09;的使用 STM32CUBEMX 使用教程2 — GPIO的使…

微信小程序实现table表格

微信小程序没有table标签&#xff0c;运用display:table和display:flex实现一个内容字数不固定表格…… wxml&#xff1a; <view class"ContentShow"> <view class"conht">烟台市新闻发布会登记审批表</view> <view class"tabl…

MySQL 基本面试题

目录 一、SQL的基本操作 1、SQL查询的执行顺序 2、count(*)、count(1) 、count(列名) 的区别 3、char 和 varchar 的区别 4、MySQL 中常用的基础函数 5、MySQL的执行流程 6、MyISAM和InnoDB的区别 二、事务 1、事务的基本概念 2、事务的四大特性&#xff08;ACID) 3…

WPF学习笔记(12)下拉框控件ComboBox与数据模板

下拉框控件ComboBox与数据模板 一、ComboBox1. ComboBox概述2. ItemsControl类3. Selector类4. ComboBox类 二、ComboBox数据模板总结 一、ComboBox 1. ComboBox概述 ComboBox类代表一个有下拉列表的选择控件&#xff0c;供用户选择。 官方文档&#xff1a;https://learn.mic…

Docker for Windows 设置国内镜像源教程

在使用 Docker 时&#xff0c;由于默认的 Docker Hub 镜像源位于国外&#xff0c;国内用户在拉取镜像时可能会遇到速度慢或连接不稳定的问题。为了加速镜像拉取&#xff0c;可以将 Docker 配置为使用国内镜像源。以下是适用于 Windows 系统的详细配置方法&#xff1a; 方法一&…

一键部署AI工具!用AIStarter快速安装ComfyUI与Stable Diffusion

AIStarter部署AI工具&#xff0c;让AI开发更简单&#xff01;无需研究复杂环境配置&#xff0c;AIStarter平台提供一键安装ComfyUI和Stable Diffusion&#xff0c;支持多版本选择&#xff0c;快速上手。以下是详细步骤&#xff1a; 一、访问AIStarter市场 下载AIStarter&#x…

Python基础(吃洋葱小游戏)

下面我将为你设计一个"吃洋葱小游戏"的Python实现方案&#xff0c;使用Pygame库开发。这个游戏模拟吃洋葱的过程&#xff0c;玩家需要收集不同种类的洋葱以获得高分&#xff0c;同时避免吃到辣椒。 &#x1f9c5; 吃洋葱小游戏 - Python实现方案 &#x1f3ae; 1. …

Objective-C 路由表原理详解

在 Objective-C 中实现路由表是组件化架构的核心&#xff0c;它通过 URL 映射机制实现模块间解耦通信。以下是完整实现原理&#xff1a; 一、核心架构设计 #mermaid-svg-5jMinPiZe8mivAbi {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fil…

通过交互式网页探索传输现象-AI云计算数值分析和代码验证

传输过程涉及质量、动量和能量等物理量在各种系统中的基本运动和转移&#xff0c;主要分为动量传输、热量传输和质量传输&#xff0c;在工程、环境科学、生物学和物流等领域至关重要。 传输过程是指物理量&#xff08;如质量、动量和能量&#xff09;在物理、化学、生物或工程系…

使用Rust原生实现小波卡尔曼滤波算法

一、算法原理概述小波变换&#xff08;Wavelet Transform&#xff09;通过多尺度分解将信号分为高频&#xff08;细节&#xff09;和低频&#xff08;近似&#xff09;部分&#xff0c;高频通常包含噪声&#xff0c;低频保留主体信息。使用Haar小波&#xff08;计算高效&#x…