前置知识: MySQL

联合索引与最左前缀原则

00:00
1 min Advanced 2026/6/14

MySQL联合索引与最左前缀原则:索引结构、匹配规则、跳列场景与索引设计策略

1. 联合索引结构

联合索引(复合索引)是在个列上创建的索引,按照定义列的顺序在 B+排序

-- 创建联合索引
CREATE INDEX idx_abc ON table_name(a, b, c);

-- B+树排序规则:
-- 先按 a 排序,a 相同按 b 排序,b 相同按 c 排序
-- 索引项:(1,1,1), (1,1,2), (1,2,1), (2,1,1), (2,2,1)

2. 最左前缀原则

2.1 匹配规则

联合索引 (a, b, c) 可以支持以下查询模式:

WHERE 条件使用索引说明
a = 1a最左列
a = 1 AND b = 2a, b最左两列
a = 1 AND b = 2 AND c = 3a, b, c全部列
b = 2跳过最左列
c = 3跳过最左列
b = 2 AND c = 3跳过最左列
a = 1 AND c = 3a跳过中间列 b

2.2 范围查询中断

-- 索引 (a, b, c)

-- 范围查询后的列无法使用索引
WHERE a > 1 AND b = 2       -- 只用 a,b 无法用索引
WHERE a = 1 AND b > 2 AND c = 3  -- 用 a, b,c 无法用索引
WHERE a = 1 AND b = 2 AND c > 3  -- 用 a, b, c 全部

-- 等值条件在前,范围条件在后
-- 索引设计时应将范围查询列放在最后

2.3 ORDER BY 与最左前缀

-- 索引 (a, b, c)

-- ORDER BY 可以利用索引避免 filesort
WHERE a = 1 ORDER BY b              --  使用索引排序
WHERE a = 1 ORDER BY b, c           --  使用索引排序
WHERE a = 1 ORDER BY c              --  跳过 b,需要 filesort
WHERE a = 1 AND b = 2 ORDER BY c    --  使用索引排序
ORDER BY a, b, c                    --  使用索引排序
ORDER BY b, c                       --  跳过 a
ORDER BY a DESC, b DESC, c DESC     --  降序也可用索引
ORDER BY a ASC, b DESC              --  排序方向不一致

3. 索引设计策略

3.1 列顺序原则

-- 原则1:等值条件列在前,范围条件列在后
-- 查询:WHERE status = 'active' AND created_at > '2026-01-01'
CREATE INDEX idx_status_created ON orders(status, created_at);

-- 原则2:高选择性列在前
-- 查询:WHERE city = '北京' AND gender = 'M'
-- city 选择性 > gender 选择性
CREATE INDEX idx_city_gender ON users(city, gender);

-- 原则3:考虑排序需求
-- 查询:WHERE dept_id = 5 ORDER BY salary DESC
CREATE INDEX idx_dept_salary ON employees(dept_id, salary DESC);

3.2 冗余索引检测

-- 索引 (a, b) 已经覆盖了 (a) 的功能
-- (a) 是冗余索引
CREATE INDEX idx_a ON table_name(a);       -- 冗余
CREATE INDEX idx_ab ON table_name(a, b);   -- 包含 a 的查询也能用

-- 但 (a, b) 不能替代 (b)
CREATE INDEX idx_b ON table_name(b);       -- 非冗余

-- 查看冗余索引
SELECT * FROM sys.schema_redundant_indexes;

3.3 联合索引 vs 多个单列索引

-- 场景:WHERE a = 1 AND b = 2

-- 方案1:联合索引(推荐)
CREATE INDEX idx_ab ON table_name(a, b);
-- 一次索引查找,效率高

-- 方案2:两个单列索引
CREATE INDEX idx_a ON table_name(a);
CREATE INDEX idx_b ON table_name(b);
-- 优化器可能使用 index_merge,效率不如联合索引
-- 且无法用于排序

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式