在MySQL的查询优化场景中,组合索引的使用规则一直是开发者需要重点掌握的内容,其中查询选择所有列是否会导致组合索引失效,需要结合索引的工作机制和查询的具体场景来分析。
组合索引的基本规则
组合索引是指基于多个列创建的索引,它的生效遵循最左匹配原则,也就是查询条件需要从索引的最左列开始,并且不能跳过中间的列。比如我们创建一个组合索引idx_user_age_name,包含user_id、age、name三个列,那么只有查询条件包含user_id时,索引才有可能被使用。
我们可以先创建一张测试表,并添加组合索引:
-- 创建测试用户表 CREATE TABLE `user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` varchar(32) NOT NULL COMMENT '用户ID', `age` int(11) DEFAULT NULL COMMENT '年龄', `name` varchar(50) DEFAULT NULL COMMENT '姓名', `address` varchar(200) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`), KEY `idx_user_age_name` (`user_id`,`age`,`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
查询所有列是否会导致索引失效
查询选择所有列(也就是使用SELECT *)本身并不会直接导致组合索引失效,是否失效取决于查询条件是否满足组合索引的最左匹配原则,以及查询的列是否能被索引完全覆盖。
场景1:查询条件符合最左匹配,查询所有列
当查询条件包含组合索引的最左列,且符合最左匹配原则时,即使查询所有列,组合索引也可能被使用,但此时会发生回表操作。
比如执行以下查询:
-- 查询条件包含user_id,符合最左匹配 EXPLAIN SELECT * FROM user_info WHERE user_id = '1001';
通过执行计划可以看到,key字段会显示idx_user_age_name,说明索引被使用了,但因为查询的是所有列,而索引中只包含user_id、age、name三个列,所以需要回到主键索引中查询id、address等其他列的数据,这个过程就是回表。
场景2:查询条件不符合最左匹配,查询所有列
如果查询条件不包含组合索引的最左列,那么无论是否查询所有列,组合索引都会失效。比如执行以下查询:
-- 查询条件只有age,不包含最左列user_id EXPLAIN SELECT * FROM user_info WHERE age = 20;
此时执行计划中key字段为NULL,说明组合索引没有被使用,会进行全表扫描。
覆盖索引的作用
如果查询的列全部包含在组合索引中,那么就不需要回表,这种情况称为覆盖索引,此时查询效率会更高。比如我们查询的列只有user_id、age、name,刚好是组合索引包含的列:
-- 查询列都在组合索引中,触发覆盖索引 EXPLAIN SELECT user_id,age,name FROM user_info WHERE user_id = '1001';
此时执行计划中Extra字段会显示Using index,说明使用了覆盖索引,不需要回表,查询效率更高。
常见误区说明
很多开发者认为SELECT *一定会导致组合索引失效,这其实是不准确的。SELECT *的问题在于:
- 会查询所有列,大概率无法触发覆盖索引,导致回表操作,增加查询开销
- 如果表结构后续新增了列,查询返回的列会更多,可能进一步降低查询效率
- 如果查询条件不符合最左匹配原则,即使不是
SELECT *,索引也会失效
所以并不是SELECT *直接导致索引失效,而是它容易让查询无法使用覆盖索引,同时如果搭配不符合规则的查询条件,就会让索引失效的问题更明显。
总结
组合索引是否失效的核心判断依据是查询条件是否符合最左匹配原则,查询选择所有列本身不会直接导致索引失效,但会增加回表的概率,降低查询效率。在实际开发中,建议尽量只查询需要的列,优先使用覆盖索引,同时保证查询条件符合组合索引的最左匹配规则,这样才能最大程度发挥组合索引的作用,提升查询性能。