最左匹配原则

MySQL的B+树索引遵循最左匹配原则,确保联合索引的有效利用。当查询条件包含联合索引的最左侧字段时,索引才可被有效使用。不遵循此原则可能导致索引失效,例如仅查询索引中右侧字段的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么会有这个 最左匹配原则?

答 : mysql 底层使用的索引是 B+ 树 , B+ 树的存放方式是 从左到右依次有序【特定的结构】,我们写sql时用到联合索引,按照索引的数据结构,按照特定的方式写查询 sql 的条件,最大化的提高查询速度。

最左匹配原则是什么?

简单来讲:在联合索引中,只有左边的字段被用到,右边的才能够被使用到。

左边是带头大哥, 必须在

假如我们创建联合索引 create index idx_a_b on shopTable(a,b);

有如下B+树

在这里插入图片描述

我们看到 最左边的a 都是有序的,分别是 : 1,1,2,2,3,3 但是右边的b 不一定有序: 1,2,1,4,3,2

但是在a都为 1 的情况下 b是有序的, 如: a=1时 b =1,2 ; a=2时, b= 1,4; a=3时 ,b=1,2;

如果我们筛选数据的时候, 直接筛选b ,整个就是无序的,需要做全表扫描

如果先a,再b 那么 ,就可以利用树来加快查找速度。

联合索引失效的情形

即不满足最左匹配原则

假如建立如下索引

create index idx_name_age on admin(name,age);

mysql> show index from admin;
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| admin |          0 | PRIMARY      |            1 | admin_id    | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| admin |          1 | idx_name_age |            1 | name        | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
| admin |          1 | idx_name_age |            2 | age         | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

  • name和age都走了索引的情况
mysql> explain select * from admin where name='1' and age=2;
+----+-------------+-------+------------+------+---------------+--------------+---------+-------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key          | key_len | ref         | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------------+------+----------+-------+
|  1 | SIMPLE      | admin | NULL       | ref  | idx_name_age  | idx_name_age | 44      | const,const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
  • 单查age , 未用到索引
mysql> explain select * from admin where age=2;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | admin | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
  • 单查name, 用到了索引
mysql> explain select * from admin where name='1';
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key          | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | admin | NULL       | ref  | idx_name_age  | idx_name_age | 39      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

可以看到, 使用了左边字段 name查 ,可以使用索引, 用了右面的age查,无法用到索引

这里只列举这一种索引失效的情况 ,其余还有: 范围值之后失效

  • 这种情况下: 由于name使用了范围索引, 导致后面的age 没有走索引
mysql> explain select * from admin where name > '1' and age = 1;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | admin | NULL       | range | idx_name_age  | idx_name_age | 39      | NULL |    1 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)
<think>好的,用户之前已经问过联合索引的命中问题,现在又接着问索引的最左原则。我需要确认自己对这个概念的理解是否正确,并且用用户容易理解的方式解释清楚。 首先,最左前缀原则是联合索引中的核心概念。用户可能已经知道联合索引的存在,但想深入了解其工作原理。我需要从基础开始,逐步展开,避免使用过于专业的术语,但又要准确。 需要明确最左原则的定义:查询条件必须从联合索引的最左边列开始,并且不能跳过中间的列。比如索引是(a,b,c),查询条件有a,或者a和b,或者a、b、c都能用上索引。但如果是b和c,或者a和c,就可能无法命中。这时候可能需要举例说明,让用户更直观。 还要注意范围查询的情况,比如当使用a > 1这样的范围条件时,后面的b列可能无法使用索引进行查找,只能用于排序。这点用户可能容易忽略,需要特别说明。 另外,用户可能想知道为什么会有这样的限制。这时候可以简单解释索引的结构,比如B+树的结构下,索引是按照最左列先排序,再排后面的列,所以必须从左到右使用。比如,先按a排序,a相同的情况下按b排序,以此类推。所以如果跳过a,直接查b,数据库无法有效利用这个索引的结构。 还需要涵盖一些常见误区,比如查询条件的顺序是否影响索引命中。比如,即使查询条件写的是b和a,优化器可能会调整顺序,所以最左原则关注的是是否存在最左列,而不是条件的顺序。这时候可以用例子说明,WHERE b=2 AND a=1其实还是可以用到(a,b)索引,因为优化器会调整顺序。 另外,用户可能想知道如何验证是否命中了索引,这时候可以提到EXPLAIN命令,查看key和key_len等字段,这在实际应用中很有帮助。之前的回复已经提到过,这里可能需要再次强调。 还要考虑用户的实际应用场景,比如设计索引时的最佳实践,比如高频查询的字段放在左边,范围查询的列尽量放在后面,避免创建冗余索引等。这些建议能帮助用户更好地设计索引,提升性能。 最后,总结最左原则的重要性,以及如何正确应用,避免常见的错误。确保用户理解后能够实际应用到数据库优化中。</think>--- ### **索引的最左原则(最左前缀原则)** **索引的最左原则**是数据库优化中联合索引使用的核心规则,它要求**查询条件必须从联合索引的最左列开始,并且不能跳过中间的列**。只有满足这一条件,数据库才能有效利用联合索引加速查询。以下是详细解析: --- ### **1. 最左原则的核心逻辑** #### **(1) 索引的物理存储结构** - 联合索引的存储方式是**按照列的顺序依次排序**的。 例如,联合索引 $(\text{col1}, \text{col2}, \text{col3})$ 的排序规则: 1. 先按 `col1` 排序; 2. `col1` 相同的情况下,按 `col2` 排序; 3. `col1` 和 `col2` 都相同的情况下,再按 `col3` 排序。 - **查询时若未指定最左列**,数据库无法跳过左侧字段直接定位右侧字段(类似电话簿无法跳过“姓氏”直接查“名字”)。 #### **(2) 最左前缀的两种形式** 1. **精确匹配最左连续字段**: ```sql -- 索引 (a, b, c) WHERE a = 1; -- ✅ 命中 a WHERE a = 1 AND b = 2; -- ✅ 命中 a, b WHERE a = 1 AND b = 2 AND c = 3; -- ✅ 完全命中 ``` 2. **范围查询后的字段可能失效**: ```sql -- 索引 (a, b, c) WHERE a > 1 AND b = 2; -- ✅ 仅命中 a(b 无法利用索引过滤) WHERE a = 1 AND b > 2 AND c = 3; -- ✅ 命中 a, b(c 无法利用索引过滤) ``` --- ### **2. 最左原则的常见场景** #### **场景1:查询条件包含最左连续字段** - **有效命中**: ```sql -- 索引 (name, age, city) WHERE name = 'Alice' AND age = 25; -- ✅ 命中 name, age WHERE name = 'Bob' AND city = 'Beijing'; -- ❌ 未命中(跳过 age) ``` #### **场景2:排序(ORDER BY)与索引顺序一致** - **有效排序**: ```sql -- 索引 (age, salary) SELECT * FROM employees ORDER BY age, salary; -- ✅ 利用索引排序 SELECT * FROM employees ORDER BY salary; -- ❌ 未利用索引 ``` #### **场景3:覆盖索引优化** - **无需回表**: ```sql -- 索引 (user_id, status) SELECT user_id, status FROM orders WHERE user_id = 100; -- ✅ 覆盖索引 ``` --- ### **3. 最左原则的典型误区** #### **误区1:查询条件的顺序无关** - **优化器会自动调整顺序**: ```sql -- 索引 (a, b) WHERE b = 2 AND a = 1; -- ✅ 命中索引优化器调整顺序为 a=1 AND b=2) ``` #### **误区2:跳过中间字段仍能部分命中** - **必须连续**: ```sql -- 索引 (a, b, c) WHERE a = 1 AND c = 3; -- ❌ 未命中(跳过 b) ``` #### **误区3:所有字段都必须参与查询** - **仅需最左连续子集**: ```sql -- 索引 (a, b, c) WHERE a = 1; -- ✅ 命中 ``` --- ### **4. 违反最左原则的后果** #### **(1) 索引失效,全表扫描** - 若未命中索引,数据库需遍历所有数据行,性能急剧下降。 ```sql -- 索引 (country, city) SELECT * FROM users WHERE city = 'Shanghai'; -- ❌ 全表扫描 ``` #### **(2) 无法利用索引排序** - 排序字段未遵循最左前缀时,需额外文件排序(File Sort)。 ```sql -- 索引 (age, salary) SELECT * FROM employees ORDER BY salary; -- ❌ 文件排序 ``` --- ### **5. 如何验证是否遵循最左原则?** 使用 `EXPLAIN` 分析执行计划: - **key** 字段显示使用的索引; - **key_len** 表示实际使用的索引字节数(可推断命中哪些列); - **Extra** 字段若为 `Using index`,表示覆盖索引优化生效。 **示例**: ```sql EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'paid'; -- key=索引名, key_len=user_id长度 + status长度 ``` --- ### **6. 最佳实践** 1. **高频查询字段放在最左侧**:优先将查询频率高的列作为联合索引的首列。 2. **范围查询列放在末尾**:避免范围查询(如 $>$, $<$)阻断后续字段的索引使用。 3. **避免冗余索引**:若已有联合索引 $(a, b)$,无需单独为 $a$ 创建索引。 4. **覆盖索引优化**:尽量让查询的列包含在索引中,减少回表操作。 --- ### **总结** - **最左原则的本质**:联合索引的物理存储顺序决定了查询必须从左到右连续使用字段。 - **设计索引时**:根据查询需求合理排列字段顺序,优先保证最左列的高筛选性。 - **验证方法**:通过 `EXPLAIN` 确认索引是否命中,避免全表扫描。 掌握最左原则,能显著提升联合索引的利用率,是数据库性能优化的关键!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值