分页场景慢?MySQL迷惑行为解读~

PostgreSQL SELECT执行原理与性能优化实战 SELECT 是关系型数据库最基础也最复杂的 SQL 操作,其本质是数据检索、计算与传输的完整生命周期。理解其背后从词法解析、查询重写、执行计划生成到 MVCC 可见性控制的底层原理,是掌握 PostgreSQL 高效查询的关键。尤其在高并发、大数据量场景下,执行计划误判、索引失效、JOIN 策略错误、JSONB 查询未优化等常见问题,会直接导致慢查询、连接池耗尽甚至服务雪崩。本文聚焦 PostgreSQL 特有的 SELECT 行为机制,结合窗口函数、CTE 递归、JSONB 路径查询、全文检索向量匹配等 阅读详情

从一个问题说起

牛牛六年前刚工作的时候,发现分页场景下,当offset变大,MySQL处理速度非常慢!具体sql如下:

select * from t_record where age > 10 offset 10000 limit 10

下表所示为表t_record结构,为了简单起见,只列了我们将讨论的字段,其余字段省略。

其中t_record是要查询的数据表,表中一共有50000条记录,age字段上有索引,且age>10的记录有20000条。

这条语句非常慢,基本达到了秒级延迟,在第二次请求有缓存之后,才变快。

在数据量这么少的情况下,走索引还这么慢,这完全不能接受,我就问我导师为什么,他反问“索引场景,MySQL中获得第n大的数,时间复杂度是多少?”

 

答案的追寻

小白直觉作答

当时只知道MySQL索引使用的是树,瞎猜了个O(logn),心想二叉树找一个节点不就是O(logn)么。自然而然,导师白了一眼,让我自己去研究。

 

继续解答

想来想去...只能从底层结构分析了,MySQL的索引是B+树。仔细想一下,就会发现通过索引去找很别扭。因为你不知道前n个数在其他子树的分布情况,也没有标记让你能快速选择去哪个子树寻找,我们无法利用B+树分支过滤的查找特性。

 

这下我明白导师的用意了——offset n,就是从第n大的数开始找!第n大的数没法使用树分支查找,所以offset,也不能!

 

回到我们一开始的问题:

select * from t_record where age > 10 offset 10000 limit 10

 

通过二级索引age,我们只能找到对应的起始节点,但无法通过树结构过滤掉10000个节点,再获取10个节点,因为我们无法知道某个子树下有多少数据,就无法通过分支进行排除。

 

那该怎么办呢?

我们来仔细看下B+树的结构,它不光有常规树的分支结构,底部还有一个由叶子节点组成链表。

显而易见,最方便最快的方式,就是用树定位到起始位置,然后直接通过叶子节点组成的链表,以O(n)的复杂度找到第n大的数据。

回到我们最初的问题,总结一下:问题的本质其实就是让offset找到第n大的数,再通过链表遍历,在数据量很大的情况下,确实会慢。

但是即使是O(n),也不至于仅有几万数据就慢得令人发指。

是不是还有其他影响因素?

 

系统学习

牛牛决定深入研究,带着问题去查找了很多资料。

这里推荐两本书,一本《MySQL技术内幕 InnoDB存储引擎》,通过它可以对InnoDB的底层机制,如acid、mvcc、索引实现、文件存储,有更深的理解。

 

第二本是《高性能MySQL》,这本书从使用层面着手,讲得比较深入,并提到了很多设计和优化的思路,对日常工作和学习都有很大的帮助。

 

两本书相结合,反复领会,MySQL就差不多能登堂入室了。

针对我们的问题,这里介绍两个相关的概念:

 

  • 聚簇索引:包含主键索引和对应的实际数据,索引的叶子节点就是数据节点;
  • 辅助索引:也叫二级节点,其叶子节点还是索引节点,并没有完整的数据,仅包含了索引值本身和主键id,用主键id反查聚蔟索引才能获取完整数据。

 

 

如图所示,offset会先从二级索引的链表顺序找10000个节点。

注意,即使这10000个节点会被扔掉,MySQL也会通过二级索引上的主键id,去聚簇索引上查一遍数据,这可是10000次随机IO,自然慢成哈士奇。

大家读到这里可能会提出疑问,为什么MySQL会有这种行为?

这和它的优化器有关系,也算是MySQL的一个大坑,时至今日,也没有优化。

 

问题的解决

针对分页性能问题,《高性能MySQL》中提到了两种方案,让我们一起来看看:

 

方案一:产品上绕过

根据业务实际需求,看能否替换为上一页、下一页的功能,这样子就可以通过和上次返回数据进行比较,搭上树分支过滤的便车。

特别在ios,android端,以前那种完全的分页是不常见的。即转换为如下sql,第一次last_id传0即可。

select * from t_record where id > last_id  limit 10

 

优点

1.能利用树的分支结构,过滤掉第n个数之前的数据集;

2.直接通过主键索引查找,省略了二级索引查找过程,性能会更高。

 

缺点

1.使用场景其实是受限制的。比如,如果是针对age字段有条件判断,再分页,那么使用主键id查找就不满足需求;

2.把主键id暴露出去了,这个本身不应该是业务层面关心的字段。

可以看到,该方案在我们的场景中,是不适用的。

因为我们还有age做过滤条件,此时用大于主键id的方式,虽然看起来变成顺序IO了,但由于是根据主键id排列来寻找,而不是根据需要的age索引,所以会导致MySQL去查更多的数据。虽然不符合我们案例的需求,但还是来看看优缺点:

方案二:正面刚

这里先介绍一个概念:

索引覆盖:当辅助索引查询的数据只有主键id和辅助索引本身,那么就不必再去查聚簇索引。

思路如下:

select * from t_record id in
(select id from t_record where age > 10 offset 10000 limit 10)

这句话是说,先从条件查询中,查找数据对应的数据库唯一id值,因为主键在辅助索引上就有,所以不用回归到聚簇索引的磁盘上拉取。

如此以来,offset部分均不需要去反查聚蔟索引,只有limit出来的10个主键id会去查询聚簇索引,这样只会十次随机IO。

在业务确实需要用分页的情况下,使用该方案可以大幅度提高性能。通常能满足性能要求。

 

优点

1.维持了分页需求,适用所有limit offset场景,大大减少随机IO,提高了性能;

2.二级索引上,只查找id,传输的数据包也变小。

 

缺点

二级索引上还是会走下面的链表来遍历,这部分时间复杂度还是O(n)。

方案选型

如果产品本身的需求,是分上下页,且没用其他过滤条件,可以用方案一。

方案二更具有普适性,同时由于合理分表的大小,一般也就500w,二级索引上O(n)的查找损耗,通常也在可接受范围。

 

总结

从一个小问题,往下深究,不仅可以深入理解这个问题,在面试和工作中大放异彩,同时在探索的过程中,自身的知识储备也能得到拓展,是技术的一个提升捷径。祝大家工作顺利,牛牛码特!

推荐阅读

为什么阿里巴巴的程序员成长速度这么快?

纳尼?SpringCloud要被淘汰了?

《飞马计划》到底是什么? 可以让数万程序员为之着迷

进大厂也就这回事,工作2到3年后进大厂操作指南

看完三件事

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。

关注公众号 『 Java斗帝 』,不定期分享原创知识。

同时可以期待后续文章ing🚀

团队AI编程工具选型指南:从上下文协同到架构推演 AI编程工具已超越单人代码补全,进入团队协作新阶段。其核心原理是通过融合代码库、项目管理(如Jira)、沟通平台(如飞书)等多源异构数据,构建可执行的‘最小有效上下文’,从而降低知识同步成本、减少Git冲突与语义不一致风险。技术价值体现在提升PR一次通过率、加速新人Onboarding、支撑架构级影响分析等工程实效;典型应用场景覆盖Java微服务开发全流程——从需求解析、接口契约生成、事务边界提示,到慢SQL优化与灰度上线验证。本文聚焦真实团队落地,深度解析GitHub Copilot、Trae Solo与 阅读详情

相关推荐

SpringBoot+Vue+MySQL 高校学科竞赛平台 完整可运行版(源码+文档)

本项目基于SpringBoot+Vue+MySQL构建高校学科竞赛管理平台,覆盖学生、教师、领队教师、管理员四大角色,实现竞赛发布、报名、刷题、评分、公示等全流程闭环管理。系统架构清晰,技术主流,配套完整源码、数据库脚本、万字论文、开题报告、答辩PPT及部署文档,支持一键运行,适用于毕业设计、课程设计及院系二次开发,真正实现“开箱即用”。

招风的黑耳优快云 304

数据库入门实战:从SQL卡顿到高可用的工程能力基线

数据库是现代应用的数据中枢,其核心在于平衡‘快、稳、省’三重目标。理解B+树索引如何影响ORDER BY与LIMIT执行路径、掌握MVCC与事务隔离级别的实际代价、识别主从复制与备份恢复中的脆弱环节,是开发者与运维人员必备的基础能力。本文聚焦MySQL等主流关系型数据库在真实生产环境中的关键决策点:复合索引设计、慢查询根因定位、连接池调优、物理备份+binlog时间点恢复,以及Orchestrator自动故障转移等工程实践。不讲抽象范式,只解‘为什么查得慢’‘为何一加索引就锁表’‘备份恢复为何耗时六小时’等

weixin_30470643的博客 463

SpringBoot+Vue+MySQL 民宿在线预定平台 完整可运行版(源码+文档)

本文介绍一套基于SpringBoot+Vue+MySQL的民宿在线预订平台,涵盖用户与管理员双角色全流程功能,实现房源展示、订单管理、支付模拟、数据看板等闭环业务。系统架构清晰,前后端分离,附带完整源码、数据库脚本、万字论文、答辩PPT及部署文档,适合毕设、课程设计或小型民宿二次开发,开箱即用,快速落地。

招风的黑耳优快云 193

Big O表示法实战指南:程序员的算法性能体检报告

Big O表示法是衡量算法时间与空间复杂度的核心工具,它剥离硬件、语言、环境等干扰因素,专注刻画输入规模n增大时资源消耗的增长阶。其本质是渐进上界分析,强调最坏情况下的可预测性,为系统稳定性提供保守保障。在工程实践中,O(1)、O(log n)、O(n)、O(n log n)构成高效服务的基石,而O(n²)常成为高并发场景下的性能分水岭。理解并推导Big O,能帮助开发者在写for循环、设计数据库查询或选择数据结构前,预判代码在真实流量下的表现。本文结合电商搜索、N+1查询、内存排序等典型场景,手把手解析如

weixin_30555515的博客 380

PaddleOCR GPU部署:从环境配置到避坑实战指南

本文详细介绍了PaddleOCR GPU部署的全过程,从环境配置到避坑实战指南。通过分析常见的部署失败原因,提供硬件兼容性自查、软件环境精配方案以及路径配置的解决方案,帮助用户高效完成GPU加速的OCR任务部署,避免90%的常见错误。

weixin_30839881的博客 419

QT绘制饼图+柱状图+折线图

使用qt绘制,折线图,饼图,柱状图,多柱状图

梅山 3879

AI的“智慧虚妄感”:大模型原理、失真与工程验证

在自然语言处理与人工智能技术快速迭代的当下,大语言模型(LLM)凭借流畅的语言生成能力带来前所未有的交互体验,但同时也引发了关于“AI是否只是模仿智慧”的讨论。从技术原理看,LLM本质是概率化的文字接龙,通过注意力机制和海量语料学习语言模式,而非掌握客观真理。这种机制导致AI幻觉、知识陈旧、上下文丢失等问题,在代码生成、技术问答等真实场景中可能输出看似专业实则虚构的内容。为建立可靠的使用边界,工程实践中引入模型评测、多次采样、交叉验证、对抗性测试等方法,并结合RAG检索增强生成、提示词工程与工具调用,构建“

weixin_30376509的博客 410

统信UOS开发环境支持Java

集成了JDK和多种IDE,为开发者提供了从代码编写、编译、调试到部署的一站式开发解决方案。

RZer的博客 2256

MySQL 索引深入理解:B+ 树、二级索引、联合索引与查询优化

理解二级索引后,就可以理解回表了。SELECT *MySQL 的执行过程分为三个步骤。覆盖索引(Covering Index)并不是一种独立的索引类型,而是一种查询效果。SQL 查询需要的所有字段,都能够直接从某个索引中获得,不需要再访问聚簇索引获取其他字段。例如:因为user_id已经包含在二级索引中,所以 MySQL 可以直接返回结果。不需要回表。联合索引(Composite Index)是同时使用多个字段建立的索引。它的排序规则是:首先按照user_id排序。当user_id。

m0_64642997的博客 140

【HarmonyOS 5】鸿蒙APP使用【团结引擎Unity】开发的案例教程

以下是基于团结引擎开发鸿蒙Unity应用的详细案例教程,整合环境配置、工程适配、跨语言通信等核心环节。

2201_75709314的博客 2485

[信号与系统]一阶与二阶连续时间系统和离散时间系统

定义:一阶连续时间系统由一阶线性常系数微分方程描述: dy(t)dt+ay(t)=bx(t) \frac{dy(t)}{dt} + a y(t) = b x(t) dtdy(t)​+ay(t)=bx(t)时间常数:时间常数 τ=1a\tau = \frac{1}{a}τ=a1​ 是系统响应速度的衡量指标。时间常数越小,系统响应越快。冲激响应:一阶系统的冲激响应是指数衰减或增长的形式。例如,对于一个单位冲激输入,响应为: h(t)=bae−at h(t) = \frac{b}{a} e^{-at} h(t)=

Andius的博客 2123

一篇文章讲清 MySQL 索引:聚簇索引、联合索引、回表与 EXPLAIN

以订单查询为例,拆解 InnoDB 聚簇索引与二级索引的存储和回表路径,解释联合索引的列序、覆盖与 ICP,再用 EXPLAIN 判断扫描、排序和优化器选择,给出可复现的排查方法。

qq_74421990的博客 290

Ansys 19 Mechanical 流体密封分析

start point是一个特殊的概念,在仿真中ansys将从start point开始搜索会发生流体渗漏的点,可以简单理解为从start point开始,向四周逐个节点比较节点上的接触压紧力与流体压力,如果流体压力大于压紧力,则发生渗漏。事实上此处的最后一个参数是指定start point类型的,为1代表这是一个“open”的start point。在通常情况下,如果不人为指定start point,程序会自动寻找指定流体压力面的“边界”,对于二维情况,就是曲线的两个端点,对于三维情况就是曲面的边线。

Dio980的博客 1537

MySQL 中 DISTINCT 与 GROUP BY 哪个效率更高?

DISTINCT与GROUP BY在纯去重场景下,MySQL 8.0 中执行计划通常一致,效率基本相同。老版本(8.0.13 之前)GROUP BY有隐式排序开销,DISTINCT往往更快。需要聚合或HAVING时,只能用GROUP BY。效率的真正决定因素是索引和执行计划,而不是这两个关键字本身。所以,与其问「哪个更快」,不如问「我的查询有没有走对索引」。

2601_96709915的博客 339

物联网低功耗广域网NB-IoT开发(一):初识NB-IoT

(二)NB-IoT的关键特性: (三)NB-IoT的应用场景: 二、NB-IOT介绍

weixin_49763156的博客 854

生成EtherCAT从站XML图片信息方法

详细介绍了EtherCAT从站XML文件中图片元素的生成方法。

kevin1499的博客 2130

4. 关系型数据库-MySQL-Canal 进阶

Canal 是基于 MySQL binlog 的增量数据订阅工具,可实现数据库变更的实时捕获。它通过伪装从库订阅 binlog,无需业务代码侵入,支持缓存同步、搜索索引更新、数据异构、实时入仓及汇总宽表增量更新等场景。使用时需开启 ROW 格式 binlog,配置专用账号,并通过 canal-server 接收事件,下游消费者处理后确认。注意 binlog 保留期、正则过滤写法及全量初始化等关键点,避免数据丢失或误判。

princemilo的博客 149

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

mysql常见问题汇总

按「现象 → 排查 → 解法」整理,按事故频率排序。

qq_38636133的博客 183

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

基于 FastAPI+LangChain+LangGraph+Agent+Vue3+MySQL 的房产数据采集与房价预测分析平台

本文介绍一个完整的「房产数据采集+AI房价预测」全栈项目,涵盖FastAPI异步后端、LangGraph Agent智能问答、爬虫采集、机器学习预测与Vue3前端,实现从数据采集到AI交互的闭环。项目融合多技术栈,具备真实业务场景与生产级设计(如降级策略、流式输出、多模型对比),兼具简历亮点与答辩演示优势,可系统性提升工程能力,并附高频面试题解析,是理想的技术综合实践项目。

深耕开发,专注编程实战。分享源码解析、项目搭建、问题排查笔记,沉淀技术,持续更新。 248

MySQL 事务:转账中途断电,钱为什么没有丢

本文系统讲解 MySQL 事务的原理与实践:以转账场景引入原子性、一致性、隔离性、持久性四大保证,剖析脏读、不可重复读、幻读三类并发异常与四个隔离级别的取舍,解读 undo log、redo log、锁与多版本并发控制的底层实现,并给出事务粒度控制与异常回滚的编码建议。

大模型全栈工程师 · Thanks_ks 310

MYSQL-多表设计

在项目开发中,在进行各个数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构。由于业务之间相互关联,所有各个表结构之间也存在各种联系。

weixin_61074074的博客 173

微服务架构下的MySQL设计实战

微服务架构下的 MySQL 交付,核心不是追求最先进的技术方案,而是建立一套边界清晰、可评审、可监控、可回滚的规范体系。分库分表解决容量与写入扩展,读写分离解决读扩展,索引优化与慢查询治理解决日常性能问题,变更管控与备份容灾守住交付底线。把这些实践嵌入需求评审、开发自测、测试压测、上线灰度、运维巡检的每个环节,并明确各自的适用边界与常见误区,才能真正让数据库成为微服务交付的稳定底座,而不是随时可能引爆的风险点。

流水账 765

mysql初阶--数据库设计

本文系统阐述数据库设计的核心方法论,从范式理论(1NF、2NF、3NF)出发,揭示数据冗余与操作异常的根源,强调3NF为工程实践的最优平衡点。通过E-R图构建实体关系模型,实现从业务需求到表结构的清晰映射。文章厘清类、实体、表三者对应关系,提出“抽象→建模→落地”的设计流程,帮助开发者建立可复用的数据库设计思维框架,避免“拍脑袋”建表的陷阱。

2601_97033068的博客 715

MySQL报Too many open files?句柄耗尽的排查与参数配置

文章讲清 max_connections 与 open_files_limit 两个额度、句柄被谁占走、分区表为什么最容易踩,给出从 error log 到 /proc/pid/limits 的定位顺序与句柄预算算法。

「一个在数据库赛道上边学边分享的学妹」——聚焦国产数据库/信创方向、分享学习笔记、踩坑经验和行业观察。 337

MySQL --库的操作

基于 Unicode 9.0 规则,排序更准确,性能也更好。新库如果没有特殊兼容需求,直接让默认值生效即可,不必手动指定。后面的数字表示版本号,意思是“如果当前 MySQL 版本 ≥ 4.01.00,就执行这句话”。在老版本中比较粗糙,比如它认为某些带重音的字母和普通字母等价。连接数爆满报“Too many connections”时,找出谁占着连接不放。,所以导出文件里不含建库语句。,但 MySQL 不强制大小写,建议养成大写习惯。,更不会转换表里已经存好的数据。),必须用反引号包起来,否则语法报错。

2501_94405739的博客 249

Flink 连接器选型实战:HDFS、Kafka、MySQL 与 Doris 的分层数据架构

连接器选型不是技术炫技,而是对数据特征的准确判断。HDFS承担离线归档与批处理,靠分区和滚动策略控制文件质量。Kafka是实时链路的中枢,靠分区、攒批和事务保证吞吐与一致性。MySQL只做维表和小结果集,靠缓存和限流保护在线库。Doris承接大数据量分析写入,靠分桶、攒批和两阶段提交保证性能与准确。把这四者按数据规模、延迟要求和一致性要求分层组合,就能搭出一套既稳定又可扩展的 Flink 数据架构。

2401_83857914的博客 876
上一篇: 阿里巴巴架构师王小瑞“墙裂”推荐:RocketMQ核心实战原理
下一篇: 阿里架构师如是说:权限系统就该这么设计
Java斗帝之路
博客等级 码龄7年 2392粉丝 687原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值