当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL 查询为什么不走索引:函数列、隐式转换和范围条件怎么改

MySQL 查询为什么不走索引:函数列、隐式转换和范围条件怎么改

来源:17golang原创 2026-07-09 13:31:46 0浏览 收藏

线上慢查询日志里经常能碰到这类场景:orders 表明明给 created_atuser_id 建了索引,SQL 也写了对应的 where 过滤条件,结果 EXPLAIN 一看 key 是空,rows 扫了几十万行数据。MySQL 不走索引时,先别急着新建索引,很多时候问题出在SQL本身的写法:把函数套在索引列上、字符串和数字类型混着比较、范围条件写得不合理,都会让原本能用的索引直接失效。

要点速览
  • 索引是否被正常使用,要看 EXPLAIN 里的 keyrowstypeExtra,不要凭主观感受直接判断。
  • where 条件里对索引列做函数处理,大多没法按原索引的排序逻辑快速定位数据行。
  • 字段类型和传入值类型不匹配时,大概率会触发隐式转换,尤其是字符串类型的列用数字做比较的场景最常见。
  • 联合索引要符合最左前缀规则,等值条件放前面、范围条件放后面,不能只凭字段“都在索引里”就判定一定生效。

先确认问题不是“压根没用到已有索引”

碰到慢查询很多人的第一反应是加新索引,但生产环境里更稳妥的做法是先排查现有索引有没有机会被用上。比如业务里常见的订单表:

CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  user_id BIGINT NOT NULL,
  status TINYINT NOT NULL,
  created_at DATETIME NOT NULL,
  amount DECIMAL(10,2) NOT NULL,
  KEY idx_user_created (user_id, created_at),
  KEY idx_created (created_at)
);

如果查询响应慢,先执行一遍 EXPLAIN

EXPLAIN
SELECT id, amount
FROM orders
WHERE DATE(created_at) = '2026-07-09';

这里不需要硬背输出里的每一个字段,先抓四个核心信息就行:type 的取值是否异常,key 字段是否为空,rows 预估扫描的行数是不是太大,Extra 部分是否出现临时表、文件排序或者额外过滤逻辑。确认完现象,再回头排查SQL本身的写法。

MySQL 查询不走索引时检查函数列、隐式转换、范围过宽并改写通过的检查清单图
不走索引先别急着加新索引,先按函数列、隐式转换、范围条件过宽几个方向把SQL条件拆开逐一检查。

常见错误写法一:把函数直接套在索引列上

最容易踩坑的慢查询写法,是为了图方便按天统计数据,把 DATE() 直接套在 created_at 字段上:

SELECT id, amount
FROM orders
WHERE DATE(created_at) = '2026-07-09';

这条SQL写起来很省事,但处理逻辑变成了“先把全表每一行的 created_at 计算出日期结果,再拿结果做比较”。索引里存的是原始 created_at 的字段值,MySQL根本没法直接用这个条件去快速定位符合要求的数据范围。

更稳妥的改法,是把函数从索引列上移走,改成前后闭开的范围条件:

SELECT id, amount
FROM orders
WHERE created_at >= '2026-07-09 00:00:00'
  AND created_at 

这个改写能让 idx_created 正常按时间范围定位数据,业务语义也更清晰。日期筛选、月份筛选、按小时筛选都可以用类似思路:不要对索引列做函数处理,把条件换成索引列能直接比较的边界值。

常见错误写法二:字段类型和查询值类型不匹配

隐式转换的问题比函数列隐蔽很多。比如手机号、订单号这类业务字段经常被定义成 VARCHAR 类型,但业务代码传参的时候不小心传了数字类型:

SELECT id, user_id
FROM orders
WHERE order_no = 202607090001;

如果 order_no 是字符串类型字段,这个查询条件就有很大概率出问题。数据库为了完成两边值的比较,会自动触发类型转换,索引的利用效率会大幅下降,甚至直接变成全表扫描。更安全的写法是保证传入值的类型和字段本身的类型完全一致:

SELECT id, user_id
FROM orders
WHERE order_no = '202607090001';

这个问题在使用ORM框架拼接SQL时也很常见。代码里不要把所有查询参数都当成数字塞入,尤其是订单号、手机号、身份证号、外部流水号这类“看起来像数字但本质是字符串标识符”的字段要格外注意。

通用判断逻辑:索引列尽量保持原样,再谈优化

判断一个where条件是不是对索引友好,可以先记住一个简单的准则:索引列尽量保持完整地出现在比较条件的左侧,不要被函数、表达式和类型转换包裹住。下面这个对照表可以当作改SQL时的快速参考。

问题写法风险点推荐改法
DATE(created_at) = '2026-07-09'函数包裹索引列改成开始时间和结束时间的范围条件。
amount + 0 > 100表达式包裹索引列把运算逻辑移到比较值侧,保持 amount > 100
order_no = 202607090001字符串列和数字做比较传入字符串字面量或者绑定字符串类型参数。
LIKE '%abc'前缀不确定的模糊匹配能改成前缀匹配就用 LIKE 'abc%',否则考虑其他检索方案。

联合索引不是字段都出现就一定生效

联合索引的使用逻辑也很容易被误判。假设有联合索引 idx_user_created(user_id, created_at),下面这种写法通常能正常利用索引:

SELECT id, amount
FROM orders
WHERE user_id = 10086
  AND created_at >= '2026-07-09 00:00:00'
  AND created_at 

因为它先用 user_id 做等值过滤,再用 created_at 做范围过滤,和联合索引的字段排序顺序完全匹配。反过来,如果只过滤 created_at,没有对应的 user_id 等值条件,这个联合索引大概率没法被利用,可能需要单独建时间字段的索引,或者调整现有的查询逻辑。

还有一种常见情况是范围条件在联合索引里放得太早。联合索引里一旦碰到范围条件,后面的字段能不能继续被充分利用,要看优化器的具体判断和条件的形态。实际写SQL的时候,不要只看查询涉及的字段是不是都在索引里,一定要用 EXPLAIN 查看真实的访问路径。

用 EXPLAIN 反向验证改写的实际效果

改完SQL之后,不要凭感觉就判定应该走索引了。至少要用 EXPLAIN 对比改写前后的执行计划结果。

EXPLAIN
SELECT id, amount
FROM orders
WHERE user_id = 10086
  AND created_at >= '2026-07-09 00:00:00'
  AND created_at 

重点关注几个核心信号:

  • key 字段是否从空变成了预期的索引名,比如 idx_user_created
  • rows 字段的预估扫描行数是不是有明显下降。
  • type 字段的取值是不是从 ALL 变成 rangeref 这类更合理的访问方式。
  • Extra 字段里有没有明显的额外排序、临时表或者大量的后置过滤逻辑。
MySQL 使用 EXPLAIN 检查 key、rows、Extra 来验证索引改写效果的检查板
SQL改写完成后要用EXPLAIN检查key、rows、type和Extra四个字段,确认索引访问路径真的得到了优化。

兼容注意:不要为了走索引改动业务逻辑

优化SQL的时候要注意一个核心原则:不要为了让索引看起来生效,把原有的业务语义改出问题。比如按天筛选数据的时候,结束时间最好用下一天的开区间,不要直接写成 23:59:59。如果字段本身带微秒精度,后者很容易漏掉部分符合条件的数据。

另外,隐式转换的问题不能只靠在SQL层补引号来解决。最好回到代码里的参数绑定位置,确认字段定义类型、参数传入类型、序列化方式三者是完全一致的。不然这条SQL临时修好了,后续同一段代码生成的其他查询还是会踩到同样的坑。

相关问题

MySQL 不走索引是不是一定要新建索引?

不一定。先排查SQL是不是把索引列包进了函数、表达式或者触发了隐式转换。如果是写法问题,改SQL往往比新建索引的收益更高、风险更小。

EXPLAIN 里 key 字段有值就代表优化完成了吗?

不代表。还要看 rowstypeExtra。有时候虽然用到了索引,但实际扫描的数据范围仍然很大,查询效果未必能达到预期。

LIKE 查询一定不能用索引吗?

不是。LIKE 'abc%' 这种前缀匹配的写法通常还是有机会利用索引,LIKE '%abc' 这种前面字符不确定的模糊匹配就很难靠普通B+Tree索引快速定位数据。

联合索引的字段顺序应该怎么排?

要结合实际业务的查询条件来排序。通用思路是等值过滤字段放前面,范围字段往后放,同时参考字段区分度、排序需求和实际查询频率,最后用 EXPLAIN 验证实际效果。

收尾检查

MySQL 查询不走索引时,先别急着堆叠新索引。更稳妥的排查顺序是:确认现有可用索引,跑 EXPLAIN 看执行计划,逐一检查函数列、隐式转换、范围条件和联合索引顺序的问题,再对比改写前后的 keyrowstype 几个核心指标。如果SQL写法已经完全符合规范,但扫描范围仍然过大,再考虑补索引、拆分查询或者调整数据存储模型。按这个流程处理,慢查询优化才不会变成反复盲目加索引的无效操作。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go map 并发读写为什么会 panic:加锁、单协程和 sync.Map 怎么选Go map 并发读写为什么会 panic:加锁、单协程和 sync.Map 怎么选
上一篇
Go map 并发读写为什么会 panic:加锁、单协程和 sync.Map 怎么选
Go 1.22 循环变量升级:闭包、goroutine 和测试回归怎么处理
下一篇
Go 1.22 循环变量升级:闭包、goroutine 和测试回归怎么处理
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ljg-skills -
    ljg-skills
    ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
    4396次使用
  • MELO音乐 - AI 音乐生成平台,支持多模态创作能力
    MELO音乐
    MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
    4066次使用
  • UniScribe - AI 免费在线音视频转文字平台
    UniScribe
    UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
    4050次使用
  • 剧云 - 免费 AI 智能中文剧本创作平台
    剧云
    剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
    4235次使用
  • 万象有声 - AI 一站式有声内容创作平台
    万象有声
    万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
    4205次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码