Mysql 索引失效的情况总结

本文详细探讨了数据库索引失效的多种原因,包括查询条件不当、统计信息失效、索引自身问题等,并提供了相应的解决办法。

1. 随着表的增长,where条件出来的数据太多,大于15%,使得索引失效(会导致CBO计算走索引花费大于走全表)

2. 统计信息失效      需要重新搜集统计信息

3. 索引本身失效      需要重建索引

下面是一些不会使用到索引的原因

索引失效
1) 没有查询条件,或者查询条件没有建立索引
2) 在查询条件上没有使用引导列
3) 查询的数量是大表的大部分,应该是30%以上。
4) 索引本身失效
5) 查询条件使用函数在索引列上(见12)
6) 对小表查询
7) 提示不使用索引
8) 统计数据不真实
9) CBO计算走索引花费过大的情况。其实也包含了上面的情况,这里指的是表占有的block要比索引小。
10)隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 由于表的字段tu_mdn定义为varchar2(20),
但在查询时把该字段作为number类型以where条件传给Oracle,这样会导致索引失效.
错误的例子:select * from test where tu_mdn=13333333333;
正确的例子:select * from test where tu_mdn='13333333333';
11)对索引列进行运算导致索引失效,我所指的对索引列进行运算包括(+,-,*,/,! 等)
错误的例子:select * from test where id-1=9;
正确的例子:select * from test where id=10;
12)使用Oracle内部函数导致索引失效.对于这样情况应当创建基于函数的索引.
错误的例子:select * from test where round(id)=10;
说明,此时id的索引已经不起作用了 正确的例子:首先建立函数索引,
create index test_id_fbi_idx on test(round(id));
然后 select * from test where round(id)=10; 这时函数索引起作用了 1,<> 2,单独的>,<,(有时会用到,有时不会)
3,like "%_" 百分号在前.
4,表没分析.
5,单独引用复合索引里非第一位置的索引列.
6,字符型字段为数字时在where条件里不添加引号.
7,对索引列进行运算.需要建立函数索引.
8,not in ,not exist.
9,当变量采用的是times变量,而表的字段采用的是date变量时.或相反情况。
10, 索引失效。
11,基于cost成本分析(oracle因为走全表成本会更小):查询小表,或者返回值大概在10%以上
12,有时都考虑到了 但就是不走索引,drop了从建试试在
13,B-tree索引 is null不会走,is not null会走,位图索引 is null,is not null 都会走
14,联合索引 is not null 只要在建立的索引列(不分先后)都会走,
in null时 必须要和建立索引第一列一起使用,当建立索引第一位置条件是is null 时,
其他建立索引的列可以是is null(但必须在所有列 都满足is null的时候),
或者=一个值;当建立索引的第一位置是=一个值时,其他索引列可以是任何情况(包括is null =一个值),
以上两种情况索引都会走。其他情况不会走。

 

转自:http://blog.youkuaiyun.com/colin_liu2009/article/details/7301089

<think>好的,我现在需要帮助用户了解MySQL索引失效的常见场景及解决方法。首先,我需要回顾用户提供的引用资料,整理出主要的信息点。用户引用了5个来源,其中提到了多种索引失效情况,比如使用OR、函数、类型转换、范围查询后的列等。 首先,我应该将这些失效场景分门别类,确保每个原因都清晰明了。比如,用户提到查询条件中有OR可能导致失效,但如果有覆盖索引的话可能不会失效,这点需要特别说明。另外,使用函数或计算会导致索引失效,比如DATE_ADD的例子。类型转换,比如字符串字段传数字,也会导致失效,需要解释隐式转换的问题。 接下来是范围查询后的索引失效,引用2提到虽然范围查询后可能失效,但优化器可能部分使用索引,这里需要详细说明。还有IS NULL/IS NOT NULL的情况,特别是OR组合可能导致全表扫描。 然后,解决方法部分需要对应每个场景给出建议,比如避免在WHERE中使用函数,使用覆盖索引,优化查询条件等。同时,用户可能需要知道如何通过EXPLAIN来分析查询计划,检查索引使用情况。 在组织内容时,要确保结构清晰,分点列出常见场景,每个场景下说明原因和解决方法。同时注意引用对应的来源,比如引用3提到OR条件,引用4提到函数和类型转换,引用2提到范围查询后的情况等。 另外,用户可能需要实际例子来更好地理解,比如在说明类型转换时,可以举一个字符串字段传入数值的例子,导致隐式转换索引失效。对于OR条件,可以说明当使用覆盖索引时可能仍然有效,但一般情况会导致失效,需要拆分成UNION。 最后,需要检查是否有遗漏的情况,比如负向查询如NOT IN、!=等,引用5提到NOT NULL的情况,这些也需要涵盖进去。同时,总结部分要强调设计表结构和编写查询时的注意事项,以及如何利用EXPLAIN工具进行验证。 现在,确保每个部分都有对应的引用标注,并且语言通俗易懂,结构分明。可能还需要注意用户提到的LaTeX格式是否正确,但根据用户的问题,这部分主要是文本描述,可能不需要数学公式。不过如果有涉及计算的例子,需要用行内或独立的LaTeX格式。例如,在解释索引失效时,如果有表达式可能需要使用$...$,但根据用户的问题,可能不涉及数学公式,所以重点放在文本描述上。 总结一下,回答需要包括: 1. 常见场景分点列出,每个场景有原因和解决方法 2. 对应的引用标注 3. 实际例子说明 4. 总结性的建议和使用工具的方法 检查是否有覆盖用户提供的所有引用信息,确保没有遗漏,比如引用3提到的OR情况,引用4的函数和类型转换,引用2的范围查询后的处理,引用5的IS NOT NULL和OR组合等。然后组织成用户要求的格式,使用中文回答,结构清晰,问题相关部分生成相关问题。</think>### MySQL索引失效的常见场景与解决方法 #### 一、常见索引失效场景及原因 1. **查询条件中包含`OR`** - **原因**: 当`WHERE`条件中使用`OR`连接多个非索引字段时,优化器可能选择全表扫描。例如: ```sql SELECT * FROM user WHERE user_id = 1 OR age > 20; -- 若age未建索引,则索引失效 ``` [^3] - **例外**: 若所有字段均被索引覆盖(覆盖索引),仍可能使用索引。例如: ```sql SELECT user_id FROM user WHERE user_id = 1 OR age > 20; -- 若(user_id, age)是联合索引 ``` 2. **对索引字段使用函数或计算** - **原因**: 索引存储的是原始值,计算或函数会破坏索引结构。例如: ```sql SELECT * FROM example WHERE DATE_ADD(birthtime, INTERVAL 1 DAY) = '2023-10-01'; -- 使用DATE_ADD导致失效[^4] ``` 3. **隐式类型转换** - **原因**: 字段类型与传入值类型不一致时,MySQL会进行隐式转换。例如: ```sql SELECT * FROM user WHERE phone = 13800138000; -- phone字段为varchar类型,传入数值导致转换 ``` [^4] 4. **范围查询后的索引失效** - **原因**: 范围查询(如`>`、`<`、`BETWEEN`)后的索引列可能无法使用索引。例如: ```sql SELECT * FROM user WHERE age > 20 AND name = 'John'; -- 若索引是(age, name),则name可能失效 ``` [^2] 5. **使用`IS NULL`或`IS NOT NULL`与`OR`组合** - **原因**: `IS NULL`或`IS NOT NULL`与`OR`联合使用时,可能触发全表扫描。例如: ```sql SELECT * FROM user WHERE user_id IS NOT NULL OR age IS NOT NULL; -- 若user_id或age未完全覆盖索引 ``` [^5] 6. **负向查询(`!=`、`NOT IN`)** - **原因**: 负向条件可能导致优化器认为全表扫描更高效。例如: ```sql SELECT * FROM user WHERE status != 'active'; -- 若status字段区分度低,索引可能失效 ``` [^4] --- #### 二、解决方法 1. **优化查询条件** - 避免在`WHERE`子句中对索引字段使用函数或计算。 - 确保传入值的类型与字段类型一致。例如,将数值转换为字符串: ```sql SELECT * FROM user WHERE phone = '13800138000'; ``` 2. **利用覆盖索引** - 若必须使用`OR`,尝试通过覆盖索引减少扫描范围。例如: ```sql CREATE INDEX idx_user_age ON user(user_id, age); ``` 3. **调整索引顺序** - 对于联合索引,将等值查询字段放在范围查询字段前。例如,将`(age, name)`改为`(name, age)`。 4. **拆分复杂查询** - 将`OR`条件拆分为`UNION`查询: ```sql SELECT * FROM user WHERE user_id = 1 UNION SELECT * FROM user WHERE age > 20; ``` 5. **使用`EXPLAIN`分析** - 通过`EXPLAIN`命令检查索引使用情况,例如: ```sql EXPLAIN SELECT * FROM user WHERE phone = '13800138000'; ``` --- #### 三、总结 设计表结构时需注意字段类型和索引合理性,编写SQL时避免触发隐式转换、函数操作等行为。通过`EXPLAIN`工具可验证索引是否生效,结合覆盖索引、查询拆分等方法可显著提升性能[^1]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值