Mysql索引失效的情况

本文总结了MySQL中可能导致索引失效的几种情况:1) 使用OR操作符时;2) like查询以%开头的模糊匹配;3) 多列索引仅第一列有效;4) 字符串类型查询未正确引用或转换;5) MySQL认为全表扫描更快时不使用索引。了解这些情况有助于优化数据库查询性能。

前提:

开发中遇到索引失效,遂查阅相关博客学习了解,得出如下Mysql索引失效情况。

情况:

1、条件中带有or,则条件中有条件带索引都会失效。

2、使用模糊查询中,like后模糊查询字符串以%开头,则查询字段索引失效。如‘%thh’。

3、多列索引中,只有第一部分的索引生效,其余部分失效。

4、查询字段是字符串类型,则若转换了查询字段类型或查询数据未用‘ ’引用,则索引失效。

如Date(str_time)、str_name=123,索引失效。

5、mysql认为全表查询比索引快,则不使用索引。

参考博客:

参考博客:MySQL索引失效原理是什么?

<think> 我们正在回答用户关于MySQL索引失效情况的问题。根据引用内容,我们可以总结一些常见的索引失效情况,并补充其他常见情况。 注意:引用[1]和引用[2]提供了部分索引失效的场景,我们需要结合这些引用并补充其他常见情况。 常见的索引失效情况包括但不限于以下情况: 1. 使用否定条件:当使用`!=`、`<>`、`NOT IN`、`NOT LIKE`等否定操作符时,索引可能会失效。 示例:`SELECT * FROM orders WHERE status != 'completed';` [^1] 2. 使用函数:在WHERE子句中对索引列使用函数时,索引失效。 示例:`EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE LEFT(student.name,3) = 'abc';` [^2] 但可以优化为使用LIKE:`EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name LIKE 'abc%';`(此时会使用索引)[^2] 3. 使用计算:在WHERE子句中对索引列进行算术运算或其他计算时,索引失效。 示例:`EXPLAIN SELECT SQL_NO_CACHE id, stuno, NAME FROM student WHERE stuno+1 = 900001;` [^2] 4. 类型转换:如果索引列是字符串类型,而查询条件中使用了数字(或者反之),会导致索引失效。 示例:`SELECT * FROM user WHERE phone = 13800138000;`(phone是varchar类型) 5. OR条件使用不当:如果OR条件中有一个列没有索引,那么即使其他列有索引,整个查询也不会使用索引。 示例:`SELECT * FROM table WHERE column1 = 'value' OR column2 = 'value';` 如果column2没有索引,则整个查询不会使用索引。 6. LIKE以通配符开头:当使用LIKE且通配符在开头时,索引失效。 示例:`SELECT * FROM user WHERE name LIKE '%abc';` 7. 复合索引未遵循最左前缀原则:对于复合索引,如果查询条件不是从索引的最左列开始,或者跳过了中间列,索引可能失效。 示例:有复合索引`(a, b, c)`,查询条件为`b=1`或`c=1`,或者`a=1 and c=1`(跳过了b)等。 8. 使用IS NULL或IS NOT NULL:在某些情况下,使用IS NULL或IS NOT NULL可能会导致索引失效。但这取决于表数据的具体情况(例如,如果该列不允许为NULL,则优化器可能使用索引)。 9. 范围条件右边的列:在复合索引中,如果某个列使用了范围条件(比如>、<、between等),则其右边的列无法使用索引。 示例:复合索引`(a, b, c)`,条件`a=1 and b>10 and c=2`,那么c列不能使用索引。 10. 数据分布影响:如果MySQL优化器发现全表扫描比使用索引更快(例如,表中数据量很小,或者满足条件的行数占大部分),则可能不使用索引。 11. 使用IN:在MySQL中,使用IN通常还是会使用索引的,但如果IN中的值过多,优化器可能会认为全表扫描更快,从而不使用索引。不过这不是绝对的失效,需要根据具体情况而定。 12. 使用连接查询时,连接条件字符集不一致:当两个表进行连接时,如果连接条件的字符集不同,会导致索引失效。 我们可以根据这些情况来组织回答,并给出相应的示例和解决方案。 注意:引用[3]是关于EXPLAIN语句结果列的解释,我们在解释索引失效时,可以通过EXPLAIN来查看是否使用了索引(key列显示为NULL表示未使用索引)。 此外,我们还需要生成相关问题。 </think> ### MySQL索引失效的常见情况及解决方案 #### 一、操作符导致失效 1. **否定操作符失效** 在使用`!=`, `<>`, `NOT IN`, `NOT LIKE`等否定条件时,索引通常失效: ```sql -- 索引失效示例(status字段有索引idx_status) SELECT * FROM orders WHERE status != 'completed'; SELECT * FROM orders WHERE status NOT IN ('completed', 'shipped'); -- [^1] ``` **解决方案**: - 改为正向条件:`status IN ('pending', 'processing')` - 使用覆盖索引:`SELECT status FROM orders WHERE status != 'completed'` 2. **范围查询右侧失效** 复合索引中,范围查询(`>`, `<`, `BETWEEN`)之后的列无法使用索引: ```sql -- 复合索引 (a,b,c) SELECT * FROM table WHERE a=1 AND b>10 AND c=2; /* 仅用到a,b */ ``` #### 二、表达式处理导致失效 3. **函数操作失效** 对索引列使用函数会使索引失效: ```sql -- 失效(LEFT函数) SELECT * FROM student WHERE LEFT(name,3) = 'abc'; -- [^2] ``` **解决方案**: ```sql -- 改为LIKE前缀匹配(利用索引) SELECT * FROM student WHERE name LIKE 'abc%'; -- [^2] ``` 4. **计算表达式失效** 索引列参与计算会失效: ```sql -- 失效(stuno字段有索引) SELECT * FROM student WHERE stuno+1 = 900001; -- [^2] ``` **解决方案**: ```sql -- 隔离计算部分 SELECT * FROM student WHERE stuno = 900001 - 1; ``` #### 三、数据结构导致失效 5. **隐式类型转换失效** 数据类型不匹配触发隐式转换: ```sql /* phone是varchar类型 */ SELECT * FROM users WHERE phone = 13800138000; /* 失效 */ ``` **解决方案**: ```sql SELECT * FROM users WHERE phone = '13800138000'; /* 有效 */ ``` 6. **LIKE通配符前缀失效** 前导通配符使索引失效: ```sql SELECT * FROM products WHERE name LIKE '%apple%'; /* 全表扫描 */ ``` **解决方案**: - 使用后缀匹配:`name LIKE 'apple%'` - 添加全文索引:`ALTER TABLE products ADD FULLTEXT(name)` #### 四、优化器决策失效 7. **数据倾斜导致失效** 当满足条件的数据超过总量的$20\% \sim 30\%$时,优化器可能选择全表扫描: ```sql -- 订单表90%状态为'completed' SELECT * FROM orders WHERE status = 'completed'; /* 可能全表扫描 */ ``` **解决方案**: - 强制使用索引:`SELECT * FROM orders FORCE INDEX(idx_status) WHERE ...` - 使用覆盖索引减少IO 8. **OR条件部分失效** 若OR条件中有非索引列,整个查询失效: ```sql -- name有索引,address无索引 SELECT * FROM users WHERE name='Alice' OR address='Beijing'; ``` **解决方案**: ```sql -- 拆分为UNION查询 SELECT * FROM users WHERE name='Alice' UNION ALL SELECT * FROM users WHERE address='Beijing' AND name!='Alice'; ``` #### 五、验证索引使用情况 使用`EXPLAIN`分析执行计划(关键字段): - **possible_keys**:可能使用的索引 - **key**:实际使用的索引(若为NULL则索引失效) - **type**:访问类型(const > ref > range > index > ALL) -- [^3] ![](https://via.placeholder.com/600x200?text=EXPLAIN输出示例图示) ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浅尝即止何来突破

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值