1. 问题现象与初步排查
最近在优化一个电商平台的订单查询接口时,遇到了一个典型问题:明明在order_id和user_id字段上建立了联合索引,但根据user_id查询用户订单列表时,响应时间仍然超过2秒。通过EXPLAIN分析执行计划后,发现实际并没有走索引扫描,而是进行了全表扫描(type=ALL)。这让我意识到在MySQL索引使用上踩了多个隐蔽的坑。
关键现象提示:当发现查询性能不符合预期时,第一时间应该使用EXPLAIN查看执行计划,重点关注type列(扫描类型)和key列(实际使用的索引)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 索引失效的六大常见原因
2.1 隐式类型转换陷阱
在最初的查询语句中,我使用了如下条件:
sql复制SELECT * FROM orders WHERE user_id = '10086';
虽然user_id字段是BIGINT类型,但查询时却用了字符串格式。MySQL在执行时会进行隐式类型转换,导致索引失效。正确的写法应该是:
sql复制SELECT * FROM orders WHERE user_id = 10086;
经验法则:WHERE条件中的值类型必须与字段定义完全一致,特别是整数与字符串、日期与字符串之间容易发生隐式转换
2.2 最左前缀原则违反
我们建立的联合索引是idx_user_order (user_id, order_id),但查询语句却是:
sql复制SELECT * FROM orders WHERE order_id = 'ORD20230701';
这种情况下,由于没有提供user_id条件,索引的最左前缀user_id缺失,导致无法使用该联合索引。这就好比电话簿按"姓+名"排序后,直接查名字是无法快速定位的。
2.3 索引列参与运算
在统计报表中有一个查询:
sql复制SELECT * FROM orders WHERE YEAR(create_time) = 2023;
虽然在create_time字段上有索引,但对其使用YEAR()函数处理后,索引就会失效。应该改为范围查询:
sql复制SELECT * FROM orders
WHERE create_time BETWEEN '2023-01-01 0
