面试-4.索引失效问题

索引失效的情况:

1.有or必全有索引;

  • 如果条件中有or,即使其中有部分条件带索引也不会使用(这也是为什么尽量少用or的原因)。
    注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引

2.复合索引未用左列字段;(索引的最左前缀原则)

  • B+ 树这种索引结构,可以利用索引的“最左前缀”,来定位记录。假设我们有(name,age)这样一个联合索引。

在这里插入图片描述
可以看到,索引项是按照索引定义里面出现的字段顺序排序的。
     因为可以支持最左前缀,所以当已经有了 (a,b) 这个联合索引后,一般就不需要单独在 a 上建立索引了。因此,第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。那么,如果既有联合查询,又有基于 a、b 各自的查询呢?查询条件里面只有 b 的语句,是无法使用 (a,b) 这个联合索引的,这时候就不得不维护另外一个索引,也就是说你需要同时维护 (a,b)、(b) 这两个索引。

3.like以%开头;

如果like查询是以%开头,那么索引将失效。如果是 '查询内容%‘ ,这种形式,索引不会失效。

4.产生了隐式类型转换;

select * from test where userId=123456;

userId的字段类型是 varchar(16),而输入的参数却是整型,所以需要做类型转换。此时就会需要走全表扫描,用不上索引。因为MySQL 中,字符串和数字做比较的话,是将字符串转换成数字。所以语句会变成下面这样,相当于给了索引上加了函数。

select * from test where  CAST(userIdAS signed int) = 123456;

5.where中索引列有运算;

修改前:
 select *
  from app a
 where 
   (a.END_DATE - sysdate) < 7
   and (a.END_DATE - sysdate) >= 0

修改后:

select *
  from app a
 where 
   a.END_DATE < sysdate + 7
   and a.END_DATE >= sysdate

6.where中索引列使用了函数;

select * from t_user where ABS(account) = 1;

可以考虑修改为

select * from t_user where (account = 1 or account = -1);

7.产生了隐式字符编码转换;

a 表的编码是 utf8mb4, b 表是utf8。

select b.* from a, b where a.userId = b.userId and a.id=2; 

因为这两个表的字符集不同,一个是 utf8,一个是 utf8mb4,所以做表连接查询的时候用不上关联字段的索引。

MySQL 内部的操作是,先把 utf8 字符串转成 utf8mb4 字符集,再做比较。这个设定很好理解,utf8mb4 是 utf8 的超集。连接过程中要求在被驱动表的索引字段上加函数操作,是直接导致对被驱动表做全表扫描的原因。

8.如果mysql觉得全表扫描更快时(数据少);

    选择索引是优化器的工作。而优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句。在数据库里面,扫描行数是影响执行代价的因素之一。扫描的行数越少,意味着访问磁盘数据的次数越少,消耗的 CPU 资源越少。MySQL 在真正开始执行语句之前,并不能精确地知道满足这个条件的记录有多少条,而只能根据统计信息来估算记录数。在频繁修改表数据的场景下,可能会出现扫描行数估计不准确的情况,可以使用analyze table t 命令,可以用来重新统计索引信息。在实践中,如果发现 explain 的结果预估的 rows 值跟实际情况差距比较大,可以采用这个方法来处理。

索引可能失效的情况:

1.唯一性差;
2.频繁更新的字段不用(更新索引消耗);
3.where中不用的字段;
4.索引使用<>时,效果一般;

什么情况下不推荐使用索引?

  1. 数据唯一性差(一个字段的取值只有几种时)的字段不要使用索引

比如性别,只有两种可能数据。意味着索引的二叉树级别少,多是平级。这样的二叉树查找无异于全表扫描。

  1. 频繁更新的字段仔细考虑使用索引

表中数据的频繁变化导致索引也频繁变化,增大数据库工作量,降低效率。.

  1. 字段不在where语句出现时不要添加索引,如果where后含IS NULL /IS NOT NULL/ like ‘%输入符%’等条件,不建议使用索引

只有在where语句出现,mysql才会去使用索引。

  1. where 子句里对索引列使用不等于(<>),使用索引效果一般
<think>好的,用户现在想了解MySQL索引失效的场景,而且需要是面试极简版。之前用户询问过MySQL的行锁在CRUD操作中的触发规则,现在转向索引失效,可能是因为他在准备面试,需要快速掌握关键点。 首先,我需要回忆常见的索引失效情况,确保覆盖主要的场景。用户需要的是极简版,所以应该分点列出,每个点简明扼要,便于记忆。同时,要使用中文,结构清晰,可能还需要例子和注意事项。 常见的失效场景包括未使用索引列、索引列使用函数或运算、类型转换、OR条件使用不当、最前缀原则、like通配符开头、范围查询后的列失效索引选择性差、使用不等于操作符、以及全表扫描更快的情况。这些点需要逐一确认是否正确,是否有遗漏。 例如,未遵循最前缀原则,比如联合索引(a,b,c),查询条件中没有a,那么索引可能无法使用。还有like以%开头的情况,会导致索引失效。这些都是面试中常见的问题,需要重点强调。 另外,用户可能需要了解每个场景的具体例子,所以在每个点下给出SQL示例会更有帮助。同时,注意事项部分可以给出优化建议,这样不仅说明问题,还提供解决方案,更符合面试回答的结构。 需要注意避免使用过于技术化的术语,但又要准确。例如,在类型转换的部分,要说明隐式转换导致索引失效,比如字符串列用数字查询,会导致类型转换,从而无法使用索引。 还要考虑用户可能存在的疑问,比如为什么范围查询后的列会失效,这时候需要解释索引的结构,范围查询后后面的列无法再用索引排序或过滤。 最后,总结部分要简明扼要,强调创建合适的索引和正确使用,避免失效场景。这样用户可以在面试时快速回忆关键点。 现在需要组织这些点,确保逻辑清晰,每个场景一个标题,例子和注意事项分开,使用表格或列表形式可能更直观,但用户要求的是极简版,所以可能不需要太复杂的格式,用编号和重点符号即可。 需要检查是否有重复或可以合并的点,比如OR条件和使用不等于操作符是否属于不同情况。是的,OR条件在非全覆盖时失效,而不等于操作符如<>或!=也会导致失效,两者不同,需要分开说明。 另外,索引选择性差的情况,如果索引列的值重复率过高,优化器可能选择全表扫描,这时候索引也会失效,这也是一个重要点。 最后,确保每个点都准确无误,没有错误信息,比如隐式类型转换的例子是否正确,比如字符串列用数字查询确实会导致转换,从而无法使用索引。 总结下来,需要分10个场景,每个场景简短说明,附例子和注意点,这样用户可以在面试中快速回答,同时展示出对问题的全面理解。</think>--- ### **MySQL索引失效场景(面试极简版)** #### **1. 未使用索引列** - **场景**:查询条件未命中索引列,直接全表扫描。 ```sql SELECT * FROM users WHERE age > 20; -- 若age字段无索引索引失效 ``` #### **2. 索引列使用函数或运算** - **场景**:对索引列进行函数操作或运算。 ```sql SELECT * FROM users WHERE YEAR(create_time) = 2023; -- 函数操作导致失效 SELECT * FROM users WHERE id + 1 = 100; -- 运算导致失效 ``` #### **3. 隐式类型转换** - **场景**:字段类型与查询值类型不匹配,触发隐式转换。 ```sql -- 假设phone字段是varchar类型 SELECT * FROM users WHERE phone = 13800138000; -- 数字转字符串,索引失效 ``` #### **4. OR条件导致失效** - **场景**:OR连接的多个条件中,存在非索引列。 ```sql SELECT * FROM users WHERE id = 1 OR age > 20; -- 若age无索引,全表扫描 ``` #### **5. 违反最前缀原则** - **场景**:联合索引未按最列匹配。 ```sql -- 联合索引(a, b, c) SELECT * FROM table WHERE b = 2; -- 缺少a列,索引失效 ``` #### **6. LIKE通配符开头** - **场景**:模糊查询以`%`开头。 ```sql SELECT * FROM users WHERE name LIKE '%张'; -- 无法走索引 ``` #### **7. 范围查询后的列失效** - **场景**:联合索引中,范围查询(`>`、`<`、`BETWEEN`)后的列无法使用索引。 ```sql -- 联合索引(a, b) SELECT * FROM table WHERE a > 1 AND b = 2; -- 仅a走索引,b失效 ``` #### **8. 索引选择性差** - **场景**:索引列重复值过多(如性别、状态字段),优化器放弃索引。 ```sql SELECT * FROM users WHERE gender = '男'; -- 若gender重复率高,可能全表扫描 ``` #### **9. 使用不等于(!=、<>)** - **场景**:`!=`或`<>`操作符可能导致索引失效。 ```sql SELECT * FROM users WHERE status != 1; -- 可能全表扫描 ``` #### **10. 优化器认为全表更快** - **场景**:当数据量小时(如100行),优化器直接全表扫描。 --- ### **总结** **核心失效原因**: - 索引未被直接使用(函数、运算、类型转换)。 - 索引结构被破坏(最前缀、范围查询)。 - 优化器主动放弃(数据量小、索引选择性差)。 **优化建议**: - 避免对索引列进行函数或运算操作。 - 联合索引按最前缀顺序设计查询条件。 - 高频查询字段尽量选择高选择性列建索引
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值