为什么MySQL会选错索引,如何解决?

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: InnoDB索引选择由优化器基于成本决策,受基数性、选择性、索引覆盖等因素影响。统计信息不准或复杂查询可能导致选错索引,可通过ANALYZE TABLE更新统计、FORCE INDEX强制索引或优化查询和配置来解决。

即使我们为表添加了索引,查询语句最终也不一定会使用索引,因为 InnoDB 是否使用索引、使用哪个索引是由优化器决定的。

SQL 优化器会分析所有可能的执行计划,并根据成本(代价)预估进行选择,倾向于选择成本最低的查询方式。这种优化器称为 CBO(基于成本的优化器)。

那么所谓的代价或成本主要与以下几个因素有关:

  1. 基数性
    索引的基数性通常指区分度,表示索引中不同取值的数量。基数性越高,索引的区分度越好,优化器越倾向于使用该索引。
  2. 选择性
    选择性反映索引过滤数据的能力。高选择性意味着索引能过滤掉更多的数据行,优化器更倾向于选择此类索引。该因素是决定扫描行数的关键,选择性越高的索引扫描行数越少。
  3. 索引覆盖
    如果查询所需的所有列都包含在索引中,即可完全通过索引获取数据,优化器会倾向于使用该“覆盖索引”,避免回表操作。
  4. ORDER BY
    当查询中包含 ORDER BY 子句时,如果排序字段上有索引,优化器为了减少文件排序(file sort),会更愿意使用该索引,因为索引本身具有顺序性。
  5. 索引类型
    不同类型的索引(如 B-TREE、HASH、FULLTEXT 等)适用于不同查询场景,优化器会根据查询类型选择最合适的索引。
  6. JOIN 类型和顺序
    对于包含 JOIN 的查询,优化器会综合考虑使用哪些索引以及 JOIN 的执行顺序。
  7. 索引的大小和深度
    较小、深度较浅的索引通常更快,因为占用磁盘空间少,能更快加载到内存中。
  8. 访问类型
    不同的访问方式,如范围查询、点查找或全表扫描,也会影响索引选择。例如某些索引结构更适用于范围查询。
  9. 内存使用
    对于大型表,优化器会评估执行计划的内存占用情况,尽量避免过度消耗内存。
  10. 系统资源限制
    优化器还会结合系统实际资源限制,如内存和磁盘 I/O 能力,进行执行计划选择。
  11. 查询缓存
    如果启用了查询缓存,且相同查询的结果已被缓存,优化器会直接使用缓存结果,而不再重新选择索引。

这里面比较重要的因素就是索引的基数性(区分度)、索引的选择性(扫描行数)、是否有索引覆盖等这几个。

由于索引选择是由以上多种因素共同决定的,因此最终选错索引可能由以下原因导致:

  1. 不准确的统计信息
    InnoDB 存储引擎依赖统计信息(如基数性、选择性等)来决定使用哪个索引。如果这些统计信息过时或不准确,优化器可能做出错误决策。
  2. 复杂的查询逻辑
    对于包含多表 JOIN、子查询、函数等复杂查询,优化器可能难以准确判断哪个索引最为有效。
  3. 系统和配置因素
    MySQL 的配置设置和系统资源限制(如内存大小)也会影响优化器的决策。

那么,如果发现 MySQL 选择了一个错误的索引,一般来说有以下几种解决方式:

  1. 更新统计信息
    定期运行 ANALYZE TABLE 命令来更新表的统计信息。这可以帮助优化器更准确地评估各个索引的有效性。
  2. 使用强制索引(FORCE INDEX)
    如果我们确定某个索引比优化器选择的更有效,可以在查询中使用 FORCE INDEX 来强制使用特定索引。
    如:SELECT * FROM clay_test_table FORCE INDEX (idx_name) WHERE name = 'CLAY';
  3. 但是,FORCE INDEX 应该谨慎使用,因为强制使用特定的索引可能会导致性能下降,特别是当表的数据分布发生变化时。在使用之前,应该确保理解该索引为什么是最好的选择,并且定期评估其效果。
  4. 优化查询
    简化查询逻辑,尽量避免复杂的连接和子查询,这有助于优化器做出更好的决策。
  5. 调整索引
    我们可以为 WHERE 条件中的过滤条件创建更合适的索引,并尽可能考虑创建复合索引来提高查询效率,尤其是对于多列的过滤和排序。
  6. 调整 MySQL 配置
    根据系统的资源和需求调整 MySQL 的配置参数,比如缓冲池大小(innodb_buffer_pool_size)。
目录
相关文章
|
1月前
|
存储 算法 关系型数据库
【Java架构师体系课 | MySQL篇】② 深入理解MySQL索引底层数据结构与算法
InnoDB索引为何采用B+树?本文由浅入深解析二叉树、红黑树、B树的缺陷,详解B+树的结构优势:非叶子节点不存数据、叶子节点有序且双向链接,支持高效范围查询与磁盘预读,三层即可存储两千多万数据,极大提升查询性能。
172 7
|
1月前
|
机器学习/深度学习 SQL 关系型数据库
TRUNCATE、DELETE、DROP 的区别?
MySQL中DELETE、TRUNCATE和DROP均用于删除数据,但作用不同:DELETE删除行记录,支持WHERE条件和事务回滚,速度慢;TRUNCATE快速清空表并重置自增ID,不可回滚;DROP则彻底删除表结构与数据,操作不可逆。三者在日志记录、速度及功能上有显著差异。
337 0
|
1月前
|
架构师 关系型数据库 MySQL
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
Explain用于分析SQL执行计划,通过模拟优化器行为揭示查询性能瓶颈。它展示索引使用、扫描行数等信息,帮助优化查询语句,提升数据库效率。
192 6
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
|
1月前
|
机器学习/深度学习 关系型数据库 MySQL
什么是脏读、幻读、不可重复读?Mysql的隔离级别是什么?
脏读、不可重复读和幻读是数据库事务并发操作中的三种异常现象。脏读指读取到未提交的临时数据;不可重复读指同一事务内两次读取结果不一致,因数据被其他事务修改;幻读则是范围查询中出现新增记录,导致行数变化。SQL-92标准定义了四种隔离级别:未提交读(RU)、提交读(RC)、可重复读(RR)和串行化(Serializable),依次增强对这些异常的防控能力,平衡数据一致性与系统并发性能。
360 0
|
1月前
|
消息中间件 架构师 Java
【Java架构师】各个微服务之间有哪些调用方式?
微服务拆分后需跨进程通信,常见方式包括HTTP调用(如RESTful、OpenFeign、@HttpExchange)、RPC框架(如Dubbo、gRPC、Thrift)、消息队列(如Kafka、RabbitMQ)及服务网格(如Istio)。不同场景下可依据性能、异步、跨语言等需求选择合适方案。
381 0
|
1月前
|
JSON 关系型数据库 MySQL
MySQL5.X和8.0有什么区别?
MySQL 8.0 相比 5.7 性能提升显著,支持 NoSQL、窗口函数、CTE、降序索引与隐藏索引,增强 JSON 处理,取消查询缓存以优化性能,默认使用 utf8mb4 编码,提升安全性、可靠性与高可用性,全面支持 ACID 事务和原子 DDL 操作。
123 5
|
1月前
|
缓存 前端开发 Java
【lattice】 lattice-dynamic-loading 深度源码分析
lattice-dynamic-loading 模块实现插件热加载与运行时扩展,通过独立类加载器保障隔离性,集成 Spring 生态,支持动态注册 Bean 与 MVC。基于策略模式、门面模式和 SPI 机制,实现高扩展性、可维护性与热部署能力,提升系统敏捷性。(239字)
88 1
|
1月前
|
消息中间件 存储 人工智能
官宣上线!RocketMQ for AI:企业级 AI 应用异步通信首选方案
RocketMQ 专门为 AI 场景推出了全新Lite Topic 模型,目前已在阿里云云消息队列 RocketMQ 版 5.x 系列实例上正式发布,并会逐步贡献到 Apache RocketMQ 开源社区,欢迎大家使用。
228 20
|
29天前
|
关系型数据库 MySQL Java
【Java架构师体系课 | MySQL篇】⑦ 深入理解MySQL事务隔离级别与锁机制
本文深入讲解数据库事务隔离级别与锁机制,涵盖ACID特性、并发问题(脏读、不可重复读、幻读)、四种隔离级别对比及MVCC原理,分析表锁、行锁、间隙锁、临键锁等机制,并结合实例演示死锁处理与优化策略,帮助理解数据库并发控制核心原理。
161 4
|
2月前
|
存储 消息中间件 Kafka
Confluent 首席架构师万字剖析 Apache Fluss(三):湖流一体
原文:https://jack-vanlightly.com/blog/2025/9/2/understanding-apache-fluss 作者:Jack Vanlightly 翻译:Wayne Wang@腾讯 译注:Jack Vanlightly 是一位专注于数据系统底层架构的知名技术博主,他的文章以篇幅长、细节丰富而闻名。目前 Jack 就职于 Confluent,担任首席技术架构师,因此这篇 Fluss 深度分析文章,具备一定的客观参考意义。译文拆成了三篇文章,本文是第二篇。
484 25
Confluent 首席架构师万字剖析 Apache Fluss(三):湖流一体