当前位置: 首页 > article >正文

MySQL的索引失效的原因有那些

1. 数据类型不匹配

详细说明:MySQL在比较不同数据类型的值时,可能会尝试进行隐式转换。如果这种转换导致了复杂度增加或无法直接利用索引,则会导致索引失效。

实例与解决方案

-- 错误示例:数据类型不匹配
select * from users where id = '123'; -- id 是 int 类型,'123' 是字符串

-- 正确示例:确保数据类型一致
select * from users where id = 123; -- 使用正确的数据类型

-- 如果必须使用字符串输入,可以显式转换
select * from users where cast(id as char) = '123';

解决方案:确保查询条件中的值与列的数据类型相匹配。如果必须使用不同类型的值,请显式地进行类型转换。在应用层面上,确保传入数据库的参数类型正确。

2. 隐式转换

详细说明:隐式转换是指 mysql 自动将一个数据类型转换为另一个数据类型。这种转换可能改变原始的查询模式,导致索引失效。

实例与解决方案

-- 错误示例:隐式转换
select * from users where age = 25 + 0.0; -- 强制浮点数运算

-- 正确示例:避免不必要的数学运算
select * from users where age = 25; -- 直接使用整数

解决方案:尽量保持查询条件简单明了,避免不必要的数学运算或其他可能导致隐式转换的操作。编写SQL语句时,确保数据类型一致性。

3. 函数或表达式

详细说明:对索引列应用函数或复杂的表达式会阻止 mysql 使用该索引,因为它需要计算每一行的结果,从而失去了索引的优势。mysql 8.0 引入了表达式索引(也称为函数索引),可以在某些情况下帮助缓解这个问题。

实例与解决方案

-- 错误示例:索引列上使用函数
select * from articles where length(title) > 10;

-- 改进方法(取决于需求)
select * from articles where title like '___________%'; -- 假设标题至少有11个字符

-- 或者创建表达式索引(mysql 8.0+)
create index idx_title_length on articles ((length(title)));
select * from articles where length(title) > 10;

解决方案:尽可能避免在索引列上使用函数。如果必须这样做,请考虑创建表达式索引或重新设计查询逻辑。对于较老版本的MySQL,重构查询以避免使用函数可能是唯一的选择。

4. 范围查询之后的列

详细说明:在复合索引中,一旦出现了范围条件,mysql 就不能再使用后续的索引部分,因为这些部分不再能够有效地缩小搜索范围。复合索引的设计应该考虑到查询模式。

实例与解决方案

create index idx_name on table (col1, col2);
select * from table where col1 = 'value1' and col2 > 'value2';

-- 如果你经常需要基于 col2 的范围查询,可以考虑创建一个单独的索引
create index idx_col2 on table (col2);

解决方案:对于频繁使用的范围查询,应该单独为涉及的列创建索引。同时,在设计复合索引时要考虑到查询模式,尽量让等值条件先于范围条件出现。

5. like 查询

详细说明like 模式以通配符开头时,mysql 不能使用索引来加速查询,因为它需要扫描所有可能的前缀。然而,如果通配符出现在模式的末尾,则索引仍然可以被使用。

实例与解决方案

-- 不理想的查询
select * from names where name like '%john%';

-- 改进方法(根据实际情况)
-- 如果是尾部模糊匹配,可以使用索引
select * from names where name like 'john%';

-- 或者使用全文索引(适用于大量文本搜索)
alter table names add fulltext(name);
select * from names where match(name) against('john');

-- 对于前缀匹配,可以使用索引覆盖
select * from names where name >= 'john' and name < 'johnz';

解决方案:尽量避免使用以通配符开头的LIKE查询。如果确实需要这样的功能,可以考虑使用全文索引或者其他专门的搜索引擎。对于前缀匹配,可以通过范围查询实现索引的有效利用。

6. or 条件

详细说明:使用 or 连接的不同列上的条件可能导致 mysql 无法有效利用索引,特别是当 or 条件跨越多个不同的列时。mysql 5.6 及以后版本支持索引合并策略,可以在某些情况下提高性能。

实例与解决方案

-- 不理想的查询
select * from users where first_name = 'john' or last_name = 'smith';

-- 改进方法(根据实际情况)
-- 如果查询频率较高,可以考虑创建组合索引
create index idx_first_last_name on users (first_name, last_name);

-- 或者重构查询逻辑,如使用 union
select * from users where first_name = 'john'
union all
select * from users where last_name = 'smith';

-- 利用索引合并(mysql 5.6+)
explain select * from users where first_name = 'john' or last_name = 'smith';

解决方案:评估是否可以通过创建组合索引或者重构查询逻辑来提高性能。对于某些情况,UNION可能是更好的选择。检查EXPLAIN输出,看看是否启用了索引合并。

7. 全表扫描更高效

详细说明:对于非常小的表或者返回大部分行的查询,全表扫描可能比使用索引更快,因为索引访问涉及到额外的 i/o 操作。mysql 优化器会权衡利弊,决定最合适的执行计划。

实例与解决方案

-- 对于小表,即使有索引也可能选择全表扫描
select * from small_table;

-- 对于大表,如果查询返回大量行,优化器也会倾向于全表扫描
select * from large_table where some_condition;

解决方案:理解MySQL优化器的行为,不要盲目依赖索引。有时候,对于特定的小表或高覆盖率查询,全表扫描是最佳选择。定期分析查询性能,确保优化器做出正确的决策。

8. 索引选择性低

详细说明:选择性低意味着索引列包含大量的重复值,使得索引的效果大打折扣。在这种情况下,mysql 可能会认为全表扫描更加高效。选择性高的索引可以显著提高查询性能。

实例与解决方案

-- 性别列的选择性很低
select * from employees where gender = 'm';

-- 改善方法(根据实际情况)
-- 尽量避免在低选择性的列上创建独立的索引,除非它们与其他高选择性的列一起组成复合索引
create index idx_gender_salary on employees (gender, salary);

解决方案:避免在选择性低的列上创建独立的索引。可以考虑与其他高选择性的列组合成复合索引。通过analyze table命令获取统计信息,评估索引的选择性。

9. 覆盖索引不足

详细说明:当查询中所选的列不在索引中时,mysql 必须回表获取完整行信息,这增加了额外的 i/o 成本,降低了索引的效率。覆盖索引可以显著减少读取时间。

实例与解决方案

-- 假设有一个覆盖索引 idx_id_name 包含 id 和 name 列
select id, name, address from customers where id = 123;

-- 改善方法
create index idx_id_name_address on customers (id, name, address);

解决方案:创建覆盖索引,即包括查询中所有需要的列。这样可以在索引中直接获取所需数据,而无需回表。注意,覆盖索引虽然提高了读取速度,但可能会影响写入性能,因此需要平衡考虑。

10. 统计信息不准确

详细说明:mysql 优化器依赖于表的统计信息来决定查询计划。如果这些统计数据过时或不准确,优化器可能会做出错误的决策。维护良好的统计信息对于优化查询至关重要。

实例与解决方案

-- 分析表以更新统计信息
analyze table your_table;

-- 或者使用 optimize table 来重建表并更新统计信息
optimize table your_table;

-- 在 mysql 8.0 及以上版本,还可以使用系统变量控制统计信息的收集
set persist optimizer_switch='histogram=on';

解决方案:定期运行analyze tableoptimize table命令来保持统计信息的准确性。这对于大型表尤其重要。在MySQL 8.0及以上版本,可以启用直方图统计信息来更好地反映数据分布。

11. 锁争用

详细说明:在高并发环境下,锁机制的存在可能导致索引效率下降,即使有合适的索引也无济于事。锁定问题不仅影响索引效率,还可能导致其他并发问题,如死锁。

实例与解决方案

-- 在高负载系统中,频繁更新某张表可能会导致读取操作等待写锁释放
-- 解决方案包括但不限于调整事务隔离级别、优化 sql 语句减少锁定时间等。

-- 降低事务隔离级别以减少锁定
set session transaction isolation level read committed;

-- 使用乐观锁策略,如添加版本号列
alter table your_table add column version int default 0;
update your_table set column1 = value1, version = version + 1 where id = specific_id and version = current_version;

解决方案:优化SQL语句以减少锁定时间,考虑适当的事务隔离级别,评估是否可以使用乐观锁策略。对于高并发环境,考虑分库分表、读写分离等架构优化措施。

使用 mysql 工具进行诊断和优化

  • explain:使用 explain 关键字查看查询执行计划,了解 mysql 是如何处理你的查询的。
  • show index:显示表的索引信息,帮助评估现有索引的有效性和适用性。
  • performance_schema:监控和诊断 mysql 性能问题,包括锁定、线程状态等。
  • slow query log:记录慢查询日志,找出那些执行时间过长的查询。
  • information_schema:访问有关数据库元数据的信息,如表结构、索引等。

       通过上述详细的讨论,我们可以看到,mysql 索引失效的问题往往可以通过合理的查询优化、索引设计和维护来解决。了解你的数据分布、查询模式以及 mysql 优化器的工作原理是构建高效数据库应用的关键。持续监控和优化数据库性能,确保索引得到充分利用,是保证应用程序响应快速和稳定的重要步骤。


http://www.kler.cn/a/453024.html

相关文章:

  • 依图科技简介
  • DP动态规划+贪心题目汇总
  • 海格通信嵌入式面试题及参考答案
  • Ubuntu网络配置(桥接模式, nat模式, host主机模式)
  • Java爬虫实战:深度解析VIP商品详情获取技术
  • 【QED】爱丽丝与混沌的无尽海
  • 企业台账系统|Java|SSM|VUE| 前后端分离
  • 【华为OD-E卷-最多提取子串数目 100分(python、java、c++、js、c)】
  • 《Vue进阶教程》(12)ref的实现详细教程
  • 高级网络工程师需要不断的学习和实践,保持对技术发展的敏锐性和洞察力,同时能够在复杂环境中解决问题和推动创新。
  • <代码随想录> 算法训练营-2024.12.19
  • uniapp+vue 前端防多次点击表单,防误触多次请求方法。
  • 解决uniapp APP端切换横竖屏,页面排版崩溃问题
  • 手机IP地址:定义、查看与切换方法
  • 地理数据库Telepg面试内容整理-分布式与高可用
  • 网络安全 | 云计算中的数据加密与访问控制
  • Java学习笔记(15)——面向对象编程
  • 一个基于Rust适用于 Web、桌面、移动设备等的全栈应用程序框架
  • YOLO11改进-注意力-引入多尺度卷积注意力模块MSCAM
  • Git:远程操作
  • 【STM32】F103ZET6开发板----笔记01
  • 图像修复和编辑大一统 | 腾讯北大等联合提出BrushEdit:BrushNet进阶版来了
  • mysql的备份和还原
  • java 核心知识点——JVM
  • 时间轮在 Netty , Kafka 中的设计与实现
  • 云原生后端开发(一)