MySQL 线上慢查询排查:隐式类型转换导致联合索引失效实录

举报
yd_218612773 发表于 2026/11/03 09:11:58 2026/11/03
【摘要】 一条看似简单的根据手机号查询用户信息的 SQL 耗时达 2 秒以上,最终排查发现入参类型不一致触发 MySQL 隐式类型转换全表扫描。本文解析排障与索引修复过程。

在线上监控中抓到一条典型的慢查询:根据手机号查询用户基础信息的接口平均响应时间超过 2000ms,在晚高峰甚至引发了数据库连接池排队。

一、慢 SQL 现场还原

表结构定义如下:

CREATE TABLE `user_account` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(64) DEFAULT NULL,
  `mobile` varchar(20) NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `idx_mobile_status` (`mobile`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

业务代码中执行的查询语句为:

SELECT id, user_name, status FROM user_account WHERE mobile = 13812345678;

二、EXPLAIN 执行计划分析

执行 EXPLAIN 查看该 SQL 的执行计划:

id: 1
select_type: SIMPLE
table: user_account
type: ALL
possible_keys: idx_mobile_status
key: NULL
key_len: NULL
rows: 852400
Extra: Using where

明明在 mobile 列上建了联合索引,而且是第一列,为什么 key 为 NULL,type 变成了 ALL 全表扫描?

三、问题根因:隐式类型转换(Type Casting)

在 MySQL 中,字符串字段(VARCHAR)与数字比较时,MySQL 的类型转换规则是将字符串转换为浮点数(DOUBLE)再进行数值对比。也就是说,上面的 SQL 在执行引擎层被等价转换成了:

SELECT * FROM user_account WHERE CAST(mobile AS SIGNED) = 13812345678;

对索引列进行了内置函数转换,破坏了 B+ 树索引的有序性,直接导致索引彻底失效,进而退化为 85 万行的全表扫描。

四、修复方案与总结

  1. 在 MyBatis/ORM 查询中显式将参数传为字符串:WHERE mobile = '13812345678'。
  2. 在应用层入口增加强类型校验与格式校验。

修复后重新 EXPLAIN:type 变为 ref,扫描行数 rows = 1,耗时降至 1ms 以内。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。