哪些情况下sql索引会失效

本文探讨了在数据库查询中导致索引失效的多种情况,包括使用or条件、未使用多列索引的第一部分、以%开头的like模糊查询、未正确引用字符串数据以及全表扫描可能比索引查询更快等。

原文:http://www.cnblogs.com/hongfei/archive/2012/10/20/2732589.html

面试时被问到这个问题,记录笔记,免得被面试的人鄙视!!

索引什么时候不会生效,以下集中情况会导致索引失效:

1.条件中用or,即使其中有条件带索引,也不会使用索引查询(这就是查询尽量不要用or的原因,用in吧)


注意:使用or,又想索引生效,只能将or条件中的每个列都加上索引

2.对于多列索引,不是使用的第一部分,则不会使用索引。

3.like的模糊查询以%开头,索引失效


4.如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不会使用索引


5.如果MySQL预计使用全表扫描要比使用索引快,则不使用索引

下面是查看索引使用情况:

show status like ‘Handler_read%’;
大家可以注意:
handler_read_key:这个值越高越好,越高表示使用索引查询到的次数
handler_read_rnd_next:这个值越高,说明查询低效

<think> 首先,用户的问题是:“我想查找MySQL索引失效的情况 请问MySQL索引失效的情况有哪些”,这是基于之前的引用内容。引用提供了MySQL索引失效的场景,具体包括: - 引用[1]:在WHERE子句中对索引列使用函数时,索引失效。例如:`SELECT * FROM orders WHERE YEAR(create_time) = 2023;`,即使有`idx_create_time`索引在`create_time`上。 - 引用[2]:走了联合索引索引没有失效的情况,但强调如果索引可用并能有效满足查询条件,MySQL会优先使用索引。 - 引用[3]:列出了6种常见场景:联合索引不满足最左匹配原则;模糊查询最前面为不确定匹配字符;索引列参与了运算;索引列使用了函数;索引列存在类型转换;索引列使用 is not null 查询。 用户要求参考这些引用,并基于上一次的问题和回答。回顾对话历史: - 系统指令:要求使用特定的LaTeX格式,结构清晰,生成相关问题等。 - 用户上一次的问题是关于MySQL索引失效的情况,我有生成回答和相关问题的义务。 在我的角色中,我必须遵循系统级指令: - 行内数学表达式用`$...$`。 - 独立公式用`$$...$$`。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾添加引用标识,如[^1]。 所以,我需要构建一个结构清晰的回答: 1. 介绍主题:MySQL索引失效的情况。 2. 列出失效场景,基于引用内容。 3. 解释每个场景的原理或示例。 4. 确保语言中文。 5. 结束时生成相关问题。 列出索引失效的主要场景,从引用中提取: - 从引用[1]:使用函数在索引列上,如`YEAR(create_time)`。 - 从引用[3]:6种场景: - 联合索引不满足最左匹配原则。 - 模糊查询最前面为不确定匹配字符(如`LIKE '%abc'`)。 - 索引列参与了运算(如`WHERE column + 1 = 10`)。 - 索引列使用了函数(与引用[1]一致)。 - 索引列存在类型转换(如`WHERE int_column = '123'`,因为类型不匹配)。 - 索引列使用 is not null 查询。 引用[2]提到索引没有失效的情况,但强调的是当索引可用时使用索引。用户问题聚焦于失效情况,所以我不需要着重那个。 组织回答结构: - 开头:简要介绍索引失效的概念。 - 主体:列出并解释失效场景。每个场景用一个点描述,包括示例代码(如果需要)。 - 结尾:总结并生成相关问题。 确保示例代码使用正确格式。系统指令说“生成相关问题”,所以我必须在结束时添加相关问题部分。 引用添加:在解释每个场景时,如果基于引用,在末尾添加[^n]。例如,提到函数使用时添加[^1]。 使用中文。 数学表达式:虽然主题是MySQL,但如果有数学内容,用LaTeX。但这里可能没有,所以可能不需要数学格式。如果有计算或表达式,用`$...$`。 例如,如果有表达式如索引扫描,但通常不需要。 现在,草拟回答: 1. **介绍**:MySQL索引失效是指查询语句无法有效利用索引进行优化,导致全表扫描,影响性能。常见的失效场景包括以下几种。 2. **失效场景**: - **场景1:在索引列上使用函数**。例如:`SELECT * FROM orders WHERE YEAR(create_time) = 2023;` 无法使用`idx_create_time`索引[^1]。原因为MySQL无法直接索引函数结果。 - **场景2:联合索引不满足最左匹配原则**。如果联合索引是`(col1, col2)`,查询只使用`col2`,索引可能失效[^3]。 - **场景3:模糊查询以通配符开头**。如`WHERE name LIKE '%abc'`,而不是`'abc%'`[^3]。因为索引是基于开头字符的。 - **场景4:索引列参与运算**。如`WHERE salary + 100 > 500`,索引在salary上无法使用[^3]。 - **场景5:索引列存在类型转换**。如`WHERE int_id = '123'`,字符串转整数可能导致索引失效[^3]。 - **场景6:使用IS NOT NULL查询**。在某些情况下,`WHERE column IS NOT NULL`可能不使用索引[^3]。 还有一些其他情况,但这些是常见的。 3. **总结**:避免这些场景可以提升查询效率。 4. **相关问题**: - 1. 如何优化MySQL查询以避免索引失效? - 2. 索引失效如何诊断? - 3. MySQL索引的工作原理是什么? 确保引用标识:在场景描述后添加[^n]。 用户真正的需求是查找索引失效的情况,所以列表要全面。 </think> ### MySQL索引失效的常见场景 在MySQL中,索引失效是指查询语句无法有效利用B-tree索引进行优化,导致数据库执行全表扫描(Full Table Scan),从而降低查询性能。索引失效通常发生在特定SQL写法或数据类型不匹配的情况下。基于参考内容,我总结了以下常见失效场景及其原因和解决方案。每个场景均基于引用原理进行解释,并附上示例查询。 #### 1. **在索引列上使用函数** - **场景描述**:在WHERE子句中对索引列应用函数(如日期函数、字符串函数等),MySQL无法直接使用索引树定位数据。 - **原因**:索引树存储原值,而函数计算改变了值,破坏了索引的有序性[^1]。 - **示例**: ```sql -- 创建索引 CREATE INDEX idx_create_time ON orders(create_time); -- 以下查询索引失效:YEAR()函数作用于create_time列 SELECT * FROM orders WHERE YEAR(create_time) = 2023; ``` - **解决方案**:改写查询避免函数,例如改用范围查询:`WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'`。 #### 2. **联合索引不满足最左匹配原则** - **场景描述**:针对联合索引(Composite Index),查询条件未从最左侧列开始使用,导致索引部分或完全失效。 - **原因**:联合索引遵循前缀匹配规则,如果跳过左侧列,索引树无法高效定位数据行[^3]。 - **示例**: ```sql -- 创建联合索引 CREATE INDEX idx_name_age ON users(name, age); -- 以下查询索引失效:未使用name列(最左侧列) SELECT * FROM users WHERE age > 30; -- 有效查询:使用name列(满足最左原则) SELECT * FROM users WHERE name = 'John' AND age > 30; ``` - **解决方案**:重组查询条件,确保优先使用索引最左列。 #### 3. **模糊查询以通配符开头** - **场景描述**:在LIKE子句中,通配符(%)出现在开头(如`'%abc'`),索引无法使用。 - **原因**:索引基于列值前缀构建,开头通配符破坏了前缀匹配机制[^3]。 - **示例**: ```sql -- 创建索引 CREATE INDEX idx_product_name ON products(name); -- 以下查询索引失效:%在开头 SELECT * FROM products WHERE name LIKE '%apple'; -- 有效查询:%在结尾,可利用前缀索引 SELECT * FROM products WHERE name LIKE 'apple%'; ``` - **解决方案**:避免开头通配符;或使用全文索引(Full-Text Index)优化模糊查询。 #### 4. **索引列参与运算** - **场景描述**:WHERE子句中索引列参与算术或逻辑运算(如加减、比较),MySQL无法直接使用索引。 - **原因**:运算改变了列值,索引树无法映射到原始数据[^3]。 - **示例**: ```sql -- 创建索引 CREATE INDEX idx_salary ON employees(salary); -- 以下查询索引失效:salary列参与加法运算 SELECT * FROM employees WHERE salary + 1000 > 5000; ``` - **解决方案**:分离运算,例如改写为`WHERE salary > 4000`。 #### 5. **索引列存在类型转换** - **场景描述**:查询条件中索引列与值类型不匹配(如字符串与数字比较),导致隐式类型转换,索引失效。 - **原因**:类型转换(如字符串转整数)破坏了索引值的精确匹配[^3]。 - **示例**: ```sql -- 创建索引(假设id列为INT类型) CREATE INDEX idx_user_id ON users(id); -- 以下查询索引失效:字符串'123'隐式转换为整数 SELECT * FROM users WHERE id = '123'; ``` - **解决方案**:确保比较数据类型一致,例如使用`WHERE id = 123`。 #### 6. **使用IS NOT NULL查询** - **场景描述**:在WHERE子句中使用`IS NOT NULL`条件时,MySQL可能忽略索引。 - **原因**:NULL值在索引中通常不存储或单独处理,优化器可能判断全表扫描效率更高[^3]。 - **示例**: ```sql -- 创建索引 CREATE INDEX idx_email ON users(email); -- 以下查询可能索引失效:尤其在NULL值较多时 SELECT * FROM users WHERE email IS NOT NULL; ``` - **解决方案**:结合其他条件缩小范围,或确保索引覆盖查询(Covering Index)。 #### 其他潜在失效场景 - **OR条件导致索引合并失败**:当OR连接的条件涉及多个索引列时,优化器可能放弃索引扫描。 - **数据分布不均**:如果索引列值重复率高(如性别列),优化器可能选择全表扫描(Cardinality过低问题)。 - **索引列使用IN子句或范围查询**:大范围的IN列表或范围查询(如BETWEEN)可能降低索引效率,但不一定完全失效[^2]。 ### 总结 MySQL索引失效主要由查询写法不当或数据类型问题引发,核心是破坏了索引的**有序性**或**前缀匹配**特性。优化时,应确保WHERE条件直接使用索引列原值,并遵循索引设计原则。实际诊断可通过EXPLAIN命令分析执行计划(如查看type列是否为index或range)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值