联合索引生效和失效的条件

本文探讨了复合或联合索引在MySQL中的使用方法及注意事项,包括如何创建有效的索引以提高查询效率,以及可能导致索引失效的具体情况。

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

联合索引生效和失效的条件

生效条件

两个或者多个列上的索引叫做复合或联合索引。
mysql中从左到右使用索引的字段,一个查询可以只使用索引中的一部分,但只能是最左侧。
创建符合索引时,应该仔细考虑列的顺序。对索引中所有列或仅对前几列执行搜索时,复合索引将会非常有用,仅对后面的任意列执行搜索时,复合索引没有任何用处。

失效条件

  • 减少或者避免 select *
  • 在使用<> 或 !=时会导致索引失并且进行全盘扫描
  • like以通配符开头 ‘%abc…’ 开头会导致索引失效,全盘扫描
  • 在索引列上做计算、函数、类型转换会导致索引失效
  • 存储引擎不能使用索引范围右边的列
  • is null not is null 无法使用索引

建议:

  • 单键索引,尽量选择对于当前select适配性更好的索引
  • 使用组合索引时,当前查询过滤性最好的字段在索引中的位置越靠前越好
  • 使用组合索引时,尽量选择可以能够包含当前查询条件中更多字段的索引
<think>嗯,用户之前问过关于区分度不高导致索引失效的问题,现在又问联合索引失效的情况。我需要先回想一下之前是怎么回答的,确保这次的内容不重复,同时又能补充新的信息。 联合索引失效可能涉及多个方面,比如索引顺序、最左前缀原则、范围查询的影响等等。首先,我应该先解释联合索引的基本概念,然后列举常见的失效场景,再给出解决方案。用户可能需要具体的例子来理解,所以每个失效情况最好都配上SQL示例。 比如,最左前缀原则是联合索引的关键点,如果查询条件中没有包含最左边的列,索引可能不会被使用。比如索引是(a,b,c),但查询只用bc,这时候索引失效了。需要具体说明这点。 然后,范围查询后的列无法使用索引,比如WHERE a > 1 AND b = 2,这时候a用了范围查询,后面的b可能无法用到索引。这也是常见的失效情况。 还有索引列使用了函数或计算,比如WHERE UPPER(a) = 'VALUE',这会导致索引失效联合索引也是一样的情况。需要提醒用户避免在索引列上使用函数。 另外,OR条件可能导致索引失效,尤其是当OR两边的条件涉及不同列时,优化器可能会选择全表扫描。例如WHERE a = 1 OR b = 2,这时候如果ab是联合索引,可能无法有效利用。 还要提到索引区分度的问题,如果联合索引中的某个列区分度太低,可能影响整体索引的效果。这用户之前的问题相关,需要联系起来。 然后,解决方案部分,应该包括遵循最左前缀、调整索引列顺序、避免范围查询、使用覆盖索引、优化查询条件等。每个方案都要具体说明,并给出示例SQL。 案例分析部分,可以举一个订单表的例子,比如索引是(user_id, status),但查询条件没有user_id,导致索引失效。或者范围查询后索引失效的情况,帮助用户更好地理解。 最后总结常见场景处理建议,用表格形式可能更清晰,用户看起来也方便。 需要确保语言口语化,避免使用专业术语过多,但又要准确。检查是否有遗漏的失效情况,比如索引列的数据类型不一致,比如字符串数字的比较,可能导致隐式转换,进而索引失效。虽然用户的问题是关于联合索引,但这也是一个常见的问题,可能需要包含在内。 另外,注意用户是希望结构清晰的回答,所以分点说明,每个部分用标题分隔,示例代码用反引号标记。同时,数学公式需要用$$...$$格式,如果有的话。 最后,确保整个回答逻辑清晰,覆盖主要失效原因解决方案,帮助用户全面理解联合索引失效的情况及应对方法。</think>--- ### **一、联合索引基础** **联合索引**(复合索引)是将多个列组合成一个索引的结构,遵循**最左前缀原则**(Leftmost Prefix Rule)。 - **存储方式**:索引按列顺序存储(例如 `(a, b, c)` 的索引,先按 `a` 排序,`a` 相同再按 `b` 排序,依此类推)。 - **核心作用**:优化多列组合查询的效率,减少回表次数。 --- ### **二、联合索引失效的常见场景** #### **1. 违反最左前缀原则** **失效原因**: 未从索引的最左列开始使用,或中间跳过某一列。 **示例**: ```sql -- 索引:INDEX(a, b, c) -- 失效查询(未使用最左列a) SELECT * FROM table WHERE b = 2 AND c = 3; -- 部分失效查询(跳过中间列b) SELECT * FROM table WHERE a = 1 AND c = 3; ``` **结果**: - 第一个查询完全无法使用索引。 - 第二个查询仅能利用索引的 `a` 列,`c` 列无法生效。 --- #### **2. 范围查询后使用其他列** **失效原因**: 若某一列使用范围查询(`>`、`<`、`BETWEEN` 等),其后的索引列将失效。 **示例**: ```sql -- 索引:INDEX(a, b, c) SELECT * FROM table WHERE a > 1 AND b = 2; ``` **结果**: - `a` 列使用范围查询后,`b` 列无法继续使用索引。 - 仅能利用 `a` 列的索引范围扫描,后续条件需回表过滤。 --- #### **3. 对索引列使用函数或计算** **失效原因**: 对索引列进行函数转换、计算或类型隐式转换,导致索引树无法匹配。 **示例**: ```sql -- 索引:INDEX(a, b) SELECT * FROM table WHERE UPPER(a) = 'VALUE'; -- 使用函数 SELECT * FROM table WHERE a + 1 = 5; -- 使用计算 SELECT * FROM table WHERE a = '123'; -- a为整型,隐式类型转换 ``` **结果**: 优化器无法直接使用索引,转为全表扫描。 --- #### **4. OR 条件导致索引失效** **失效原因**: 若 `OR` 连接的条件涉及非索引列,或不同列的组合,优化器可能放弃使用索引。 **示例**: ```sql -- 索引:INDEX(a, b) SELECT * FROM table WHERE a = 1 OR b = 2; ``` **结果**: - 若 `b` 列无独立索引,优化器会选择全表扫描。 - 若 `a` `b` 均有独立索引,可能触发 `index_merge`,但效率仍可能低于预期。 --- #### **5. 索引列区分度过低** **失效原因**: 联合索引中某一列区分度极低,导致整体过滤效率不足。 **示例**: ```sql -- 索引:INDEX(gender, phone) SELECT * FROM users WHERE gender = 'M' AND phone = '138xxxx'; ``` **结果**: - `gender` 列区分度低,需扫描大量数据,优化器可能放弃索引。 --- ### **三、解决方案** #### **1. 遵循最左前缀原则** - **设计索引时**:将高频查询列放在最左侧。 - **调整查询条件**:确保查询条件包含最左列。 ```sql -- 索引:INDEX(country, city, age) -- 有效查询 SELECT * FROM users WHERE country = '中国' AND city = '北京'; ``` #### **2. 避免范围查询后的索引列** - 将等值查询列放在范围查询列之前。 ```sql -- 原索引:INDEX(a, b) → 调整为 INDEX(b, a) SELECT * FROM table WHERE b = 2 AND a > 1; ``` #### **3. 使用覆盖索引** - 确保索引包含所有查询字段,避免回表。 ```sql -- 索引:INDEX(a, b, c) SELECT a, b, c FROM table WHERE a = 1 AND b = 2; ``` #### **4. 拆分复杂查询** - 将 `OR` 条件改写为 `UNION`,分别利用不同索引。 ```sql -- 改写前 SELECT * FROM table WHERE a = 1 OR b = 2; -- 改写后 SELECT * FROM table WHERE a = 1 UNION SELECT * FROM table WHERE b = 2; ``` #### **5. 监控索引使用情况** - 通过 `EXPLAIN` 分析执行计划,验证索引是否生效。 ```sql EXPLAIN SELECT * FROM table WHERE a = 1 AND b = 2; ``` - 关注 `key`(使用的索引 `rows`(扫描行数)。 --- ### **四、案例分析** **场景**:订单表 `orders` 有联合索引 `INDEX(user_id, status)`,但查询 `WHERE status = 2` 未走索引。 **问题原因**: - 违反最左前缀原则,未使用 `user_id` 列。 **优化方案**: 1. 调整查询条件,包含 `user_id`(如分页查询时指定用户范围)。 2. 若需单独按 `status` 查询,可增加 `status` 的独立索引(权衡写入性能)。 --- ### **五、总结** | **失效场景** | **解决方案** | |---------------------------|--------------------------------| | 未使用最左前缀列 | 调整查询条件索引顺序 | | 范围查询后使用其他列 | 将等值列前置,或拆分查询 | | 对索引列使用函数/计算 | 避免操作索引列原始值 | | OR 条件涉及不同列 | 改写为 `UNION` 或使用覆盖索引 | | 低区分度列在前 | 高区分度列优先放在最左侧 | **核心原则**: 1. **最左前缀匹配**是联合索引的基石。 2. **覆盖索引**可显著减少回表开销。 3. 通过 `EXPLAIN` 验证索引使用情况,避免盲目建索引
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值