1. 问题现象与初步排查
最近在优化一个电商平台的订单查询接口时,遇到了一个典型问题:明明在相关字段上建立了索引,但查询响应时间仍然超过2秒。通过EXPLAIN分析执行计划发现,虽然索引确实被命中了,但实际扫描的行数却高达数十万。
这种情况在数据库优化中非常常见——你以为加了索引就万事大吉,但查询性能依然不理想。经过深入排查,我发现主要踩了以下几个坑:
重要提示:索引不是银弹,建了索引不代表查询一定会快。索引的有效性取决于数据结构、查询条件、表设计等多重因素。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 索引失效的六大常见原因
2.1 隐式类型转换导致索引失效
在排查日志时发现,应用程序中有一个高频查询是这样的:
sql复制SELECT * FROM orders WHERE user_id = '10086';
而user_id字段在数据库中实际是INT类型。这个隐式的字符串到整型的转换会导致MySQL放弃使用索引。
解决方案:
- 严格保持应用程序中的数据类型与数据库一致
- 修改查询为:
WHERE user_id = 10086 - 对于无法修改代码的情况,可以考虑使用函数索引(MySQL 8.0+)
原理剖析:
MySQL在执行类型转换时,需要对每行数据应用转换函数,这使得索引的有序性失效。就好比你按字母顺序排列的电话簿,如果有人用数字来查人名,排序就失去意义了。
2.2 最左前缀原则被忽视
我们有一个复合索引idx_status_created(status, created_at),但很多查询是这样写的:
sql复制SELECT * FROM orders WHERE created_at > '2023-01-01';
这个查询无法利用复合索引,因为它没有包含最左边的status字段。
正确用法:
sql复制-- 包含status条件(即使值是范围)
SELECT * FROM orders WHERE status IN (1,2,3) AND created_at > '2023-01-01';
-- 或者调整索引顺序(如果业务允许)
ALTER TABLE orders ADD INDEX idx_created_status(created_at, status);
