最左匹配原则
PS:现在orders表中存在idx_user_id(user_id),以及idx_user_status(user_id, status)两个索引
1-例子
运行:
sql
EXPLAIN SELECT * FROM orders WHERE status = 1;
结果为:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | orders | ALL | 99520 | 10 | Using where |
分析:联合索引无法使用
2-分析
联合索引结构:
(user_id, status)
索引的排序结构实际上是:
user_id → status
可以理解为类似这样排序:
user_id=1 status=0
user_id=1 status=1
user_id=1 status=2
user_id=2 status=0
user_id=2 status=1
user_id=2 status=2
所以索引查找必须:
先确定 user_id
再确定 status
而你的 SQL:
WHERE status = 1
缺少:
user_id
数据库不知道从哪一段开始查找,因此:
无法利用索引
于是优化器选择:
全表扫描
执行计划变成:
type: ALL
3-引出概念
联合索引:
(user_id, status)
可使用的查询:
WHERE user_id = 1
WHERE user_id = 1 AND status = 1
不可使用:
WHERE status = 1
规则:
必须从索引最左列开始使用
这就是:
最左匹配原则
4-举例说明
4-1.联合索引的存储方式
假设你建了一个联合索引 (user_id, status, amount),它在底层的排序方式是
bash
(user_id, status, amount)
也就是说,索引先按 user_id 排序,再在相同的 user_id 下按 status 排序,再在相同的 (user_id, status) 下按 amount 排序
4-2.最左匹配原则的含义
查询条件必须从联合索引的最左字段开始,才能利用索引
可以用到连续的前缀字段,但一旦中间断了,就不能继续往后匹配
举例说明:
WHERE user_id = 1:能用索引,用到索引的第一列WHERE user_id = 1 AND status = 1:能用索引,用到索引的前两列WHERE user_id = 1 AND status = 1 AND amount = 100:能用索引,用到索引的三列WHERE user_id = 1 AND amount = 100:这种能用到部分索引,只能吃到user_id这一列WHERE status = 1:不能用索引,因为跳过了最左的user_idWHERE status = 1 AND amount = 100:也不能用索引,因为没有从最左的user_id开始
PS:这个和你写的sql条件的顺序不影响,你写的sql会被优化器会自动重排条件
sql
SELECT * FROM orders WHERE status = 1 AND user_id = 1;
#status写在前,user_id写在后,依旧可以吃到(user_id, status, amount)索引
5-删除冗余索引
因为联合索引和最左匹配原则:
如果现在表里有一个(user_id)单列索引和(user_id, status, amount)联合索引,那么这个(user_id)单列索引可以删除了,因为联合索引由user_id开头,完全能覆盖单列索引的功能