文章目录
- 一、联合索引的注意点
- 二、最左前缀原则
- 三、常见联合索引命中
- 四、特殊,且常见使用场景
一、联合索引的注意点
查询条件顺序:尽量按照索引字段顺序编写查询条件。避免跳过字段:三个字段及以上是,当查询时经常需要跳过左边字段时,考虑建立单独的索引。
覆盖索引:尽量只查询索引包含的字段。
范围查询放后:把等值(=)查询放在范围查询前面。
核心原理:MySQL的联合索引是按照字段顺序构建的B+树,必须从最左字段开始使用,不能跳过任何前面的字段。
二、最左前缀原则
最左前缀原则有两个核心,分别是最左,顺序性。
想要命中索引必须从最左字段开始使用,保持固定的顺序性,不能跳过前面的字段单独使用后面的字段,否则会导致索引失效。
如果遇到范围查询(>、<、between、like) 就会停止匹配。
创建联合索引时,尽可能把查询出现频率高的字段放在前面(左侧),尽可能多的满足最左原则。
三、常见联合索引命中
假设有一个用户表,存在联合索引, 索引的三个字段及顺序是name, age, sex
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT NOT NULL,
sex ENUM('男', '女') NOT NULL,
-- 创建联合索引,字段顺序为 name, age, sex
INDEX idx_name_age_sex (name, age, sex)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;根据最左前缀原则,下面是一些能命中索引的情况:
WHERE name = '张三' -- 命中name
WHERE name = '张三' AND age = 25 -- 命中name、age
WHERE name = '张三' AND age = 25 AND sex = '男' --完全所有字段,最优的索引使用
WHERE name = '张三' AND sex = '男' -- 仅仅命中name,由于跳过了age,顺序性中断,sex无法命中
ORDER BY name -- 排序命中name
ORDER BY name, age -- 排序命中name, age
ORDER BY name, age, sex -- 排序命中name, age, sex
WHERE name = '张三' ORDER BY age --条件匹配命中name、排序命中age创建索引时,字段及顺序是name, age, sex 和 name, sex,age 是不一样的。索引的B+树结构是按照一定的顺序组织的。如果左边的没命中索引,之后的字段也就不会命中了(和打怪升级一样,第一关都没通过,后面的二、三关也就没通过)
顺序性指的联合索引多个字段之间的顺序性,和我们自己编写sql字段的顺序无关.
执行sql时,执行器会优化sql,WHERE name = ‘张三’ AND age = 20 等效于 WHERE age = 20 AND name = ‘张三’
四、特殊,且常见使用场景
sql语句 | 命中情况 | 原因 |
WHERE age = 25 | 未命中 |
|
WHERE sex = ‘女’ | 未命中 | 由于跳过了name和age ,顺序性中断,sex无法命中; 使用ORDER BY时同理 |
WHERE age = 25 AND sex = ‘男’ | 未命中 | 由于跳过了name,顺序性中断,sex无法命中; 使用ORDER BY时同理 |
WHERE name = ‘张三’ AND sex = ‘男’ | 仅仅命中name | 由于跳过了age,顺序性中断,sex无法命中 |
WHERE name = ‘张三’ AND age > 20 | 命中name、age | name字段等值查询,age字段范围查询 |
WHERE name = ‘张三’ AND age > 20 AND sex = ‘男’ | 命中name、age,未命中sex | name字段等值查询,age字段范围查询, |
WHERE name = ‘张三’ AND age BETWEEN 18 AND 30 | 命中name、age | name字段等值查询,age字段范围查询 |
WHERE name = ‘张三’ OR address = ‘北京’ | 未命中 |
|
WHERE name > ‘张三’ | 命中name | 范围查询可以命中索引 |
WHERE name > ‘张’ AND age = 25 | 命中name,未命中age |
|
WHERE name LIKE ‘%张三%’ | 不命中name | LIKE模糊也遵循最左原则,左侧是模糊。需要逐个内容匹配,所以不命中索引 |
WHERE name LIKE ‘%张三’ | 不命中name | LIKE模糊也遵循最左原则,左侧是模糊,需要逐个内容匹配,所以不命中索引 |
WHERE name LIKE ‘张三%’ | 命中name |
|
WHERE name LIKE ‘张三’ | 命中name |
|
WHERE UPPER(name)=‘ZHANGSAN’ | 未命中 |
|
WHERE WHERE name + ‘三’ = ‘张三’ | 未命中 | 对索引字段使用函数或表达式会使索引失效 |
WHERE name != ‘张三’ | 可能命中、可能不会命中 | 不等于条件需要扫描大部分索引,优化器可能选择全表扫描,依赖优化器的自己选择 |
WHERE name IS NULL | 可能命中、可能不会命中 | 理论上可以使用索引,但通常效果不佳,优化器可能选择其他方式,依赖优化器的自己选择 |
WHERE name IS NULL | 可能命中、可能不会命中 | 理论上可以使用索引,但通常效果不佳,优化器可能选择其他方式,依赖优化器的自己选择 |
官方文档资源参考:
https://dev.mysql.com/doc/refman/8.0/en/multiple-column-indexes.html
















