MySQL索引无效的情况

SQL索引优化与失效分析

普通的索引的创建:

CREATE INDEX  (自定义)索引名  ON  数据表(字段);

复合索引的创建:

CREATE INDEX  (自定义)索引名  ON  数据表(字段,字段,。。。);

删除索引:

DROP INDEX 索引名;

索引失效分析工具:

可以使用explain命令加在要分析的sql语句前面,在执行结果中查看key这一列的值,如果为NULL,说明没有使用索引。

以下通过explain显示出mysql执行的字段内容:

  • id: SELECT 查询的标识符. 每个 SELECT 都会自动分配一个唯一的标识符.

  • select_type: SELECT 查询的类型.

  • table: 查询的是哪个表

  • partitions: 匹配的分区

  • type: join 类型

  • possible_keys: 此次查询中可能选用的索引

  • key: 此次查询中确切使用到的索引.

  • ref: 哪个字段或常数与 key 一起被使用

  • rows: 显示此查询一共扫描了多少行. 这个是一个估计值.

  • filtered: 表示此查询条件所过滤的数据的百分比

  • extra: 额外的信息

     

索引查询失效的几个情况:

1、like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效。

 

2.or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效

 

3、组合索引,不是使用第一列索引,索引失效。

 

4、数据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int型,使索引无效,产生全表扫描。

 

5、在索引列上使用 IS NULL 或 IS NOT NULL操作。索引是不索引空值的,所以这样的操作不能使用索引,可以用其他的办法处理,例如:数字类型,判断大于0,字符串类型设置一个默认值,判断是否等于默认值即可。

 

6、在索引字段上使用not,<>,!=。不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 优化方法: key<>0 改为 key>0 or key<0。

 

7、对索引字段进行计算操作、字段上使用函数。(索引为 emp(ename,empno,sal))

 

8、当全表扫描速度比索引速度快时,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输出示例图示) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值