什么是联合索引的最左前缀原则
联合索引(复合索引)是指包含多个列的索引,例如 INDEX idx_a_b_c (a, b, c)。MySQL 在使用联合索引时,会遵循最左前缀原则:查询条件必须从索引的最左列开始,并且不能跳过中间的列,才能利用该索引。
简单说,索引 (a, b, c) 相当于建立了 (a)、(a, b)、(a, b, c) 三个索引,但不会单独为 (b) 或 (c) 建立索引。
如何用 EXPLAIN 验证索引使用情况
在查询前加上 EXPLAIN 关键字,MySQL 会返回执行计划。重点关注以下列:
- key:实际使用的索引名称。如果为
NULL,表示未使用索引。 - type:访问类型,常见值从优到劣:
system>const>eq_ref>ref>range>index>ALL。ALL表示全表扫描。 - rows:预估需要扫描的行数,越小越好。
- Extra:额外信息,如
Using index表示覆盖索引,Using where表示在存储引擎层过滤。
准备测试环境
创建一张示例表并插入数据:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
age INT,
city VARCHAR(50),
INDEX idx_name_age_city (name, age, city)
);
-- 插入若干测试数据
INSERT INTO users (name, age, city) VALUES
('Alice', 25, 'Beijing'),
('Bob', 30, 'Shanghai'),
('Charlie', 35, 'Guangzhou');
各种查询场景的执行计划分析
1. 使用全部索引列
EXPLAIN SELECT * FROM users WHERE name = 'Alice' AND age = 25 AND city = 'Beijing';
结果:key 为 idx_name_age_city,type 为 ref。✅ 完全使用索引。
2. 使用最左列
EXPLAIN SELECT * FROM users WHERE name = 'Alice';
结果:key 为 idx_name_age_city,type 为 ref。✅ 使用索引。
3. 使用最左两列
EXPLAIN SELECT * FROM users WHERE name = 'Alice' AND age = 25;
结果:key 为 idx_name_age_city,type 为 ref。✅ 使用索引。
4. 跳过最左列
EXPLAIN SELECT * FROM users WHERE age = 25 AND city = 'Beijing';
结果:key 为 NULL,type 为 ALL。❌ 未使用索引,全表扫描。
5. 使用最左列和第三列(跳过中间列)
EXPLAIN SELECT * FROM users WHERE name = 'Alice' AND city = 'Beijing';
结果:key 为 idx_name_age_city,type 为 ref,但 Extra 可能显示 Using index condition 或 Using where。✅ 能使用索引,但只能用到 name 列,city 列无法用于索引查找(可能用于过滤)。
6. 范围查询后的列失效
EXPLAIN SELECT * FROM users WHERE name = 'Alice' AND age > 20 AND city = 'Beijing';
结果:key 为 idx_name_age_city,type 为 range。✅ 使用索引,但 city 列无法用于索引查找,因为 age 是范围条件。
7. 最左列使用范围查询
EXPLAIN SELECT * FROM users WHERE name LIKE 'A%' AND age = 25;
结果:key 为 idx_name_age_city,type 为 range。✅ 使用索引,但 age 列无法用于索引查找。
8. 最左列使用函数或运算
EXPLAIN SELECT * FROM users WHERE UPPER(name) = 'ALICE';
结果:key 为 NULL,type 为 ALL。❌ 未使用索引,因为对索引列使用了函数。
总结与建议
- 联合索引必须从最左列开始使用,否则无法利用索引。
- 范围查询(
>、<、BETWEEN、LIKE前缀匹配)会导致其后的列无法用于索引查找。 - 避免在索引列上使用函数或表达式,否则索引失效。
- 设计联合索引时,将选择性高(区分度大)的列放在左边,但也要考虑最左前缀原则和实际查询模式。
- 使用
EXPLAIN验证实际查询是否命中索引,是优化 SQL 的必备步骤。
通过以上示例和 EXPLAIN 的输出,你可以清晰地判断哪些查询真正用上了索引,并据此调整索引设计或 SQL 写法。