MySQL 8.0 联合索引走错:为什么加了索引查询反而从 200ms 变成 8s

发布时间:2026/10/30 22:27:05

MySQL 8.0 联合索引走错:为什么加了索引查询反而从 200ms 变成 8s 本文摘要线上订单加联合索引后从 200ms 变 8 秒索引命中却更慢。根因是 MySQL 8.0 偏好免排序索引低选择性前缀致回表暴涨。仅适用于非覆盖索引场景统计信息过期需先刷新再判断。一、问题与结论环境Docker 启动的 MySQL 8.0InnoDBSpring Boot 3.x 订单服务通过JdbcTemplate调同一条查询。表orders约 50 万行statusshipped占 15%user_id范围 1~10000初始只有idx_user_id。SELECT*FROMordersWHEREstatusshippedANDuser_id42ORDERBYcreated_atDESCLIMIT20;上线前该查询约 200ms为消除排序有人加了idx_status_created (status, created_at)同一查询涨到 8s。结论MySQL 8.0 默认prefer_ordering_indexon优化器看到联合索引能省掉 filesort 就选了它用statusshipped约 7.5 万行作前缀扫描每条都回表取user_id再过滤回表次数从约 50 次涨到数万次。索引确实命中只是命中了错的那个——这不是索引没建而是优化器的取舍在低选择性前缀下翻车。二、排查与选择依据先看优化器选了什么EXPLAINFORMATJSONSELECT*FROMordersWHEREstatusshippedANDuser_id42ORDERBYcreated_atDESCLIMIT20;三个判据依次确认key从idx_user_id变成idx_status_createdExtra却没有Using filesortFORMATJSON的cost_info里query_cost更低但rows_examined_per_scan上万——代价模型按统计采样估算索引扫描低估了非覆盖索引的回表随机 I/O回表是乘法不是加法EXPLAIN ANALYZE8.0.18的 actual rows 远大于估算直接暴露真实扫描量。若换索引后立刻出现且SHOW INDEX FROM orders显示新索引cardinality为 0 或异常则是统计信息未刷新导致的临时错选先执行ANALYZE TABLE orders;再判断。替代方案与取舍方案选择条件代价边界什么时候不该用重建联合索引(user_id, status, created_at)本文推荐该索引主要服务本查询多一个索引的写入开销需删旧索引其他查询依赖idx_status_created免排序时删改影响面大不该直接动索引IGNORE INDEX (idx_status_created)线上需快速止血SQL 与索引名强耦合索引改名即失效只适合临时数据分布变化后不会自动换回/* SET_VAR(optimizer_switchprefer_ordering_indexoff) */单条语句修正、不改表结构该语句必然走 filesort排序数据量本身很大时filesort 才是真瓶颈不该用不建议FORCE INDEX它会阻止优化器在数据分布变化后自动切换比IGNORE INDEX更危险。三、关键原理三个事实串起根因免排序偏好prefer_ordering_index启用时只要某索引能满足 ORDER BY优化器就优先选它哪怕前缀列过滤选择性很差。这是设计取舍不是 bug。回表代价被低估非覆盖索引每条匹配都要一次二级索引到聚簇索引的随机 I/O扫描条目数与回表次数是乘法关系前缀选择性越低估算偏差越被放大。统计信息延迟innodb_stats_auto_recalc默认开启但采样有延迟新增索引后立即查询可能拿着过期统计做决策。四、可运行示例环境Docker MySQL 8.0需 8.0.18 才有EXPLAIN ANALYZE。dockerrun-d--namemysql8-p3306:3306\-eMYSQL_ROOT_PASSWORDtest-eMYSQL_DATABASEdemo mysql:8.0建表与造数20 万行completed约 80%、shipped约 15%、pending约 5%。用n DIV 10000与n % 10000生成互不相关的状态和用户避免纯取模产生固定关联USEdemo;DROPTABLEIFEXISTSorders;CREATETABLEorders(idBIGINTUNSIGNEDAUTO_INCREMENTPRIMARYKEY,user_idBIGINTUNSIGNEDNOTNULL,statusVARCHAR(20)NOTNULL,amountDECIMAL(10,2)NOTNULL,created_atDATETIMENOTNULL,KEYidx_user_id(user_id))ENGINEInnoDB;SETSESSIONcte_max_recursion_depth200001;INSERTINTOorders(user_id,status,amount,created_at)WITHRECURSIVE seqAS(SELECT1nUNIONALLSELECTn1FROMseqWHEREn200000)SELECT1n%10000,CASEWHEN(nDIV10000)%2016THENcompletedWHEN(nDIV10000)%2019THENshippedELSEpendingEND,10n%990,2024-01-01INTERVAL(n*157)SECONDFROMseq;ANALYZETABLEorders;操作步骤-- 步骤 1只有 idx_user_idEXPLAINANALYZESELECT*FROMordersWHEREstatusshippedANDuser_id42ORDERBYcreated_atDESCLIMIT20;-- 步骤 2加联合索引并刷新统计ALTERTABLEordersADDINDEXidx_status_created(status,created_at);ANALYZETABLEorders;-- 步骤 3重复同一查询EXPLAINANALYZESELECT*FROMordersWHEREstatusshippedANDuser_id42ORDERBYcreated_atDESCLIMIT20;预期输出步骤 1 选中idx_user_id回表约 20 次user_id42 恰好 20 行步骤 3 的key变为idx_status_created、Extra无Using filesortactual rows 升到 3 万量级约 15% 的行需回表过滤耗时明显上涨。这是依据官方文档描述的推断绝对毫秒数未验证取决于缓冲池与机器。实际输出本文示例未在本机执行需在你的 Docker 环境运行后回填回填时重点记录EXPLAIN ANALYZE的 actual rows 与耗时并与IGNORE INDEX (idx_status_created)的结果对照。常见失败加完索引立刻 EXPLAINkey没变化或仍走旧索引。原因是新索引统计信息未生成SHOW INDEX的cardinality为 0。修复执行ANALYZE TABLE orders;后重新 EXPLAIN。五、验证结果与边界仅对非覆盖索引成立索引包含user_id变成覆盖索引后无回表差距会大幅缩小。前缀列选择性必须低匹配 15%~80% 的行才明显数据量小或缓冲池足够大时差距可能不到一秒。MySQL 5.7 没有prefer_ordering_index从 5.7 升 8.0 后同一查询计划可能改变需重新验证8.0.21 调整过代价模型小版本升级后同样要复测。SET_VAR只影响当前语句session 级关闭开关会影响该连接所有带 ORDER BY 的查询只适合排查阶段不要长期保留。参考资料MySQL 8.0 Switchable Optimizationsprefer_ordering_index 默认值MySQL 8.0 Index HintsUSE/FORCE/IGNORE INDEX 语法MySQL 8.0 Optimizer HintsSET_VAR 单语句开关MySQL 8.0 EXPLAIN 与 EXPLAIN ANALYZE 输出说明MySQL 8.0 ANALYZE TABLE索引统计刷新
延伸阅读

更多相关文章

2026/10/30 22:17:04

可执行文件分发前的防逆向清单:半小时能过一遍

可执行文件分发前的防逆向清单:半小时能过一遍 【免费下载链接】bla 🛡️ BLA (Blind LLM Agents) — Adversarial defense shield that protects binaries, Electron apps, JS bundles, Python, and WebAssembly against AI reverse-engineering agents…

2026/10/30 23:22:35

推理的一致性哈希与亲和路由-让同一用户落到同一实例

文章目录摘要一、为什么推理服务是有状态的二、一致性哈希怎么做亲和三、虚拟节点缓解倾斜四、会话与上下文的粘性五、抖动与均衡的权衡六、失效与迁移处理七、常见坑八、衔接大会专题你会在奇点智能技术大会看到什么落地清单(Checklist)工程取舍速记补充…

2026/10/30 23:22:35

训练集群的能耗与碳效率-绿色AI的工程账

文章目录摘要一、训练为什么是电老虎二、芯片与平台能效三、利用率是隐藏大户四、液冷与散热效率五、能耗与性能的非线性六、调度与错峰七、常见坑八、衔接大会专题你会在奇点智能技术大会看到什么落地清单(Checklist)工程取舍速记补充问答摘要 大模型训…

2026/10/30 23:22:35

智能体的工具描述与Schema设计-让模型用对工具

文章目录摘要一、为什么工具总被用错二、描述怎么写才清楚三、参数 Schema 的讲究四、副作用与权限显式化五、详细与成本的权衡六、工具治理与版本七、常见坑八、衔接大会专题你会在奇点智能技术大会看到什么落地清单(Checklist)工程取舍速记补充问答摘要…

2026/10/30 23:22:35

STBC MIMO-OFDM误码率分析:Alamouti编码与仿真避坑指南

简介:这套Matlab仿真代码实现基于STBC的MIMO-OFDM系统误码率分析,面向无线通信方向的学生与科研人员,重点解决多天线OFDM系统在不同调制方式下的性能评估问题。代码支持BPSK、QPSK、8PSK、16PSK四种M-PSK调制,并可在1X1、2X2、4X4…

2026/10/30 23:22:35

企业AI能力评价标准:从战略到落地的全方位指南

1. 企业AI能力评价标准的必要性作为AI应用架构师,我经常遇到企业客户提出的困惑:"我们投入了大量资源建设AI能力,但如何判断这些投入是否真正产生了价值?"这正是制定企业AI能力评价标准的核心意义所在。在过去的项目经验…

2026/10/30 20:55:10

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/30 20:55:10

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/30 20:55:09

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/30 0:00:46

NCP1342高频准谐振反激控制器:从设计约束到验收的完整方案

简介:NCP1342 高频准谐振反激控制器应用介绍译文文档,面向电源设计工程师、硬件研发人员及开关电源学习者,帮助读者跨越英文原版资料的语言门槛,系统理解这款高集成度 QR Flyback 控制器的设计要点。文档围绕芯片核心特性展开&…

2026/10/30 0:00:46

NCP1342准谐振反激电源设计:从选型到验收的全流程解析

简介:这份文档面向电源设计工程师与开关电源学习者,系统梳理NCP1342高频准谐振反激控制器的应用要点,帮助读者快速理解这款高集成度离线电源变换器控制芯片的工作机制与设计方法。内容涵盖芯片核心特性、引脚功能定义、电气特性参数表、最大额…

2026/10/30 0:00:46

Web系统自动登出机制设计与实现全解析

1. 系统自动登出机制的设计初衷在各类Web应用和后台管理系统中,自动登出功能早已成为标配。这个看似简单的功能背后,实际上涉及用户安全、资源管理和体验优化的多重考量。作为从业十多年的老开发,我见过太多因为登出逻辑设计不当导致的安全事…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑