您的当前位置:首页 >IT科技类资讯 >明明是同一条SQL,为什么有时候走索引a,有时候却走索引b ? 正文
时间:2025-11-04 21:01:34 来源:网络整理编辑:IT科技类资讯
前言想象你是一家餐厅的服务员,面前有两个菜单:菜单A:按菜品分类排列前菜、主菜、甜点)菜单B:按价格从低到高排列 当顾客说:"我要最便宜的川菜"。你会:先用菜单B找到所有低价菜从中筛选川
想象你是明明一家餐厅的服务员,面前有两个菜单:菜单A:按菜品分类排列(前菜、同条主菜、什有时候甜点)菜单B:按价格从低到高排列
当顾客说:"我要最便宜的走索走索川菜"。

你会:
先用菜单B找到所有低价菜从中筛选川菜或者:
先用菜单A找到所有川菜再按价格排序这就是引a有时引MySQL优化器的日常决策!
明明是明明同一条SQL,有时候走的同条索引a,而有时候走的什有时候索引b,就是走索走索它的锅。
今天这篇文章跟大家一起聊聊,引a有时引MySQL选错索引的明明问题,希望对你会有所帮助。同条
现在有个需求:查询今年开始已付款的前100个订单。
给status字段创建了索引idx_status。走索走索
给create_time字段创建了索引idx_create_time。引a有时引
查询订单的sql如下:
复制SELECT * FROM orders WHERE status = paid -- 状态条件 AND create_time > 2025-01-01 -- 时间条件 ORDER BY amount DESC LIMIT 100;1.2.3.4.5.周一执行计划如下:
复制使用索引:idx_status(状态索引) 扫描行数:500行 耗时:0.1秒1.2.3.周二执行计划如下:
复制使用索引:idx_create_time(时间索引) 扫描行数:50万行 耗时:8秒1.2.3.周一只扫描了500行数据,而周二却扫描了50万行数据。
周一耗时0.1秒,亿华云计算而周二耗时却又8秒。
同一SQL在不同时间性能差异80倍!
让我们拆解背后的原因。
MySQL优化器的决策流程如下:
成本计算示例:
索引名称
预估扫描行数
回表次数
排序成本
总成本
idx_status
50万
50万次
需要排序
1050分
idx_create_time
5万
5万次
无需排序
600分
根据扫描行数、回表次数、排序成本,计算一个总成本的分数。
优化器会选择总成本更低的idx_create_time索引。
场景还原:
周一数据:已支付订单5万条,其中2025年的5万条周二数据:已支付订单50万条,其中2025年的50万条这个例子中数据分布变化很大,周二的数据,比周一的数据一下子多了45万。
可能会影响总成本的分数。
我们可以通过下面的SQL查看数据分布:
复制SELECT COUNT(*) AS total, SUM(status=paid) AS paid_count, SUM(create_time>2023-01-01) AS new_orders FROM orders;1.2.3.4.5. 真凶2:统计信息过期统计信息过期,就像用去年的地图导航,新修的路不会出现在地图上。源码库
MySQL的"地图"就是统计信息。
我们可以通过ANALYZE TABLE ... DELETE STATISTICS命令删除统计信息:
复制ANALYZE TABLE orders DELETE STATISTICS;1.这时候查询可能变成全表扫描:
复制EXPLAIN SELECT...1.显示type: ALL
那么,如何解决这个问题呢?
使用ANALYZE TABLE命令,刷新统计信息(相当于更新地图):
复制ANALYZE TABLE orders;1. 真凶3:索引覆盖度差异点餐类比:
菜单A能直接看到菜品价格 → 无需问厨师(覆盖索引)菜单B只能看到菜品名 → 需要问厨师详情(回表查询)下面的SQL会走idx_status(需要回表):
复制SELECT * FROM orders WHERE status=paid;1.下面的SQL会走idx_create_time(覆盖索引):
复制SELECT create_time FROM orders WHERE create_time>2023-01-01;1.2. 真凶4:索引碎片化索引碎片化就像书本的目录页被撕破,找内容变得困难。
检查方法:
复制SHOW TABLE STATUS LIKE orders;1.查看Data_free字段,值越大碎片越多。
优化方案:
使用ALTER TABLE命令重建索引。
复制ALTER TABLE orders ENGINE=INNODB;1.使用EXPLAIN查看当前SQL的执行计划:
复制EXPLAIN SELECT * FROM orders WHERE status=paid AND create_time>2023-01-01;1.2.3.4. 第二步:检查统计信息使用SHOW INDEX命令检查索引的统计信息:
复制SHOW INDEX FROM orders;1.关注Cardinality字段,值越接近真实数据越好。
第三步:分析数据分布使用下面的SQL分析数据分布:
复制SELECT COUNT(*) AS total, AVG(LENGTH(status)) AS status_avg_len FROM orders;1.2.3.4. 第四步:追踪优化器思考过程 复制SET optimizer_trace="enabled=on"; SELECT * FROM orders WHERE ...; SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;1.2.3.开启optimizer_trace,然后通过INFORMATION_SCHEMA.OPTIMIZER_TRACE表查看追踪优化器思考过程。
使用FORCE INDEX强制使用指定索引:
复制SELECT * FROM orders FORCE INDEX(idx_status) WHERE ...;1. 方案2:创建更优索引创建更优的联合索引:
复制ALTER TABLE orders ADD INDEX idx_status_create_time(status,create_time);1.2. 方案3:定期维护计划定期统计信息更新定期碎片率检查定期索引重建电脑主机备件安装教程(手把手教你安装电脑主机备件,让你的电脑更强大)2025-11-04 20:52
电脑磁盘读取错误的解决方法(如何通过按键重启来应对磁盘读取错误)2025-11-04 20:16
电脑字体错误1907的原因与解决方法(深入解析电脑字体错误1907及应对策略)2025-11-04 20:15
V8升级EMUI5.0(华为主题升级,体验无与伦比的个性化手机界面)2025-11-04 19:52
教你如何设置戴尔电脑的启动项(详解戴尔电脑启动设置及常见问题解答)2025-11-04 19:49
2017中国Joy如何引领游戏文化风潮(游戏文化盛典——中国Joy2017精彩回顾)2025-11-04 19:39
电脑剪映草地变色教程(让你的视频草地变色不再是梦想!)2025-11-04 19:05
电脑端WPS文件显示错误的原因及解决方法(深入探讨WPS文件显示错误的几种常见情况与应对策略)2025-11-04 19:00
华为电脑MateBookXPro使用教程(轻松掌握华为MateBookXPro的使用技巧与窍门)2025-11-04 18:52
电脑皮肤特效教程(以电脑如何弄皮肤特效教程为主题,让你的桌面炫酷不一样)2025-11-04 18:41
华为电脑电源改装教程(提升华为电脑性能的完美改装指南)2025-11-04 20:30
电脑卡片手绘边框教程(用电脑卡片手绘边框,让你的作品独一无二)2025-11-04 20:19
如何通过电脑添加抖音商品(电脑抖音商品添加教程及步骤)2025-11-04 20:14
如何通过自学电脑程序设计(全面指导教程,轻松掌握编程技能)2025-11-04 19:23
装机新手必看!以装机盘为工具的装机教程大揭秘!(教你一步步轻松装机,让电脑焕然一新!)2025-11-04 19:15
电脑连网错误691的解决方法(探究错误691的原因以及应对策略)2025-11-04 18:52
如何避免以电脑保存网银密码错误的安全风险(以电脑保存网银密码错误的危害及防范措施)2025-11-04 18:47
《电脑玩穿越火线按钮教程》(快速掌握游戏技巧,畅享射击乐趣)2025-11-04 18:36
轻松学会以戴尔电脑分区桌面教程(简明易懂,快速操作)2025-11-04 18:32
华为电脑开机显示用户配置错误的问题及解决方法(华为电脑开机显示用户配置错误的原因分析与解决方案)2025-11-04 18:18