面试官:聊聊索引失效的10种场景,能回答一半就算过

今天我聊聊索引的相关问题,因为索引是大家都比较关心的公共话题,确实有很多坑。

不知道你在实际工作中,有没有遇到过下面的这两种情况:

  • 明明在某个字段上加了索引,但实际上并没有生效。

  • 索引有时候生效了,有时候没有生效。

今天就跟大家一起聊聊,mysql数据库索引失效的10种场景,给曾经踩过坑,或者即将要踩坑的朋友们一个参考。

1. 准备工作

所谓空口无凭,如果我直接把索引失效的这些场景丢出来,可能没有任何说服力。

所以,我决定建表和造数据,给大家一步步演示效果,尽量做到有理有据。

我相信,如果大家耐心的看完这篇文章,一定会有很多收获的。

1.1 创建user表

创建一张user表,表中包含:idcodeagenameheight字段。

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `code` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,
  `age` int DEFAULT '0',
  `name` varchar(30) COLLATE utf8mb4_bin DEFAULT NULL,
  `height` int DEFAULT '0',
  `address` varchar(30) COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_code_age_name` (`code`,`age`,`name`),
  KEY `idx_height` (`height`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

此外,还创建了三个索引:

  • id:数据库的主键

  • idx_code_age_name:由code、age和name三个字段组成的联合索引。

  • idx_height:普通索引

1.2 插入数据

为了方便给大家做演示,我特意向user表中插入了3条数据:

INSERT INTO sue.user (id, code, age, name, height) VALUES (1, '101', 21, '周星驰', 175,'香港');
INSERT INTO sue.user (id, code, age, name, height) VALUES (2, '102', 18, '周杰伦', 173,'台湾');
INSERT INTO sue.user (id, code, age, name, height) VALUES (3, '103', 23, '苏三', 174,'成都');

周星驰和周杰伦是我偶像,在这里自恋了一次,把他们和我放到一起了。哈哈哈。

1.3 查看数据库版本

为了防止以后出现不必要的误会,在这里有必要查一下当前数据库的版本。不说版本就直接给结论,是耍流氓,哈哈哈。

select version();

查出当前的mysql版本号为:8.0.21

1.4 查看执行计划

在mysql中,如果你想查看某条sql语句是否使用了索引,或者已建好的索引是否失效,可以通过explain关键字,查看该sql语句的执行计划,来判断索引使用情况。

例如:

explain select * from user where id=1;

执行结果:

从图中可以看出,由于id字段是主键,该sql语句用到了主键索引

当然,如果你想更深入的了解explain关键字的用法,可以看看我的另一篇文章《explain | 索引优化的这把绝世好剑,你真的会用吗?》,里面更为详细的介绍。

2. 不满足最左匹配原则

之前我已经给code、age和name这3个字段建好联合索引:idx_code_age_name。

该索引字段的顺序是:

  • code

  • age

  • name

如果在使用联合索引时,没注意最左前缀原则,很有可能导致索引失效喔,不信我们一起往下看。

2.1 哪些情况索引有效?

先看看哪些情况下,能走索引。

explain select * from user
where code='101';
explain select * from user
where code='101' and age=21 
explain select * from user
where code='101' and age=21 and name='周星驰';

执行结果:

上面三种情况,sql都能正常走索引。

其实还有一种比较特殊的场景:

explain select * from user
where code = '101'  and name='周星驰';

执行结果:

查询条件原本的顺序是:code、age、name,但这里只有code和name中间断层了,掉了age字段,这种情况也能走code字段上的索引。

看到这里,不知道聪明的你,有

<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行),优化器直接全表扫描。 --- ### **总结** **核心失效原因**: - 索引未被直接使用(函数、运算、类型转换)。 - 索引结构被破坏(最左前缀、范围询)。 - 优化器主动放弃(数据量小、索引选择性差)。 **优化建议**: - 避免对索引列进行函数或运算操作。 - 联合索引按最左前缀顺序设计询条件。 - 高频询字段尽量选择高选择性列建索引
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值