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

简介: 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)。
目录
相关文章
|
27天前
|
SQL 架构师 关系型数据库
【Java架构师体系课 | MySQL篇】⑤ 索引优化实战一
本文深入解析MySQL索引优化原理,涵盖联合索引使用、覆盖索引、索引下推、filesort排序机制及trace工具分析执行计划选择等内容,并结合实际案例提供索引设计原则与SQL优化策略。
104 5
|
1月前
|
存储 算法 关系型数据库
【Java架构师体系课 | MySQL篇】② 深入理解MySQL索引底层数据结构与算法
InnoDB索引为何采用B+树?本文由浅入深解析二叉树、红黑树、B树的缺陷,详解B+树的结构优势:非叶子节点不存数据、叶子节点有序且双向链接,支持高效范围查询与磁盘预读,三层即可存储两千多万数据,极大提升查询性能。
132 7
|
25天前
|
机器学习/深度学习 SQL 关系型数据库
TRUNCATE、DELETE、DROP 的区别?
MySQL中DELETE、TRUNCATE和DROP均用于删除数据,但作用不同:DELETE删除行记录,支持WHERE条件和事务回滚,速度慢;TRUNCATE快速清空表并重置自增ID,不可回滚;DROP则彻底删除表结构与数据,操作不可逆。三者在日志记录、速度及功能上有显著差异。
262 0
|
24天前
|
架构师 微服务
【架构师】微服务的拆分有哪些原则?
微服务拆分需遵循七大原则:职责单一、围绕业务、中台化公共模块、按系统保障级别分离、技术栈解耦、避免循环依赖,并遵循康威定律使架构与组织匹配,提升可维护性与协作效率。
120 4
|
1月前
|
消息中间件 存储 Kafka
流、表与“二元性”的幻象
本文探讨流与表的“二元性”本质,指出实现该特性需具备主键、变更日志语义和物化能力。强调Kafka与Iceberg因缺乏更新语义和主键支持,无法真正实现二元性,唯有统一系统如Flink、Paimon或Fluss才能无缝融合流与表。
130 7
流、表与“二元性”的幻象
|
26天前
|
XML Java 开发者
springboot自动装配的基本原理
Spring Boot自动装配基于“约定大于配置”理念,通过@SpringBootApplication、@EnableAutoConfiguration与spring.factories机制,结合条件注解实现智能Bean加载。它根据依赖自动配置组件,大幅简化开发。其核心是AutoConfigurationImportSelector筛选符合条件的配置类,实现按需装配。开发者可专注业务,享受“开箱即用”的便捷体验。(238字)
|
28天前
|
架构师 关系型数据库 MySQL
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
Explain用于分析SQL执行计划,通过模拟优化器行为揭示查询性能瓶颈。它展示索引使用、扫描行数等信息,帮助优化查询语句,提升数据库效率。
149 6
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
|
1月前
|
存储 人工智能 关系型数据库
钉钉ONE选用阿里云PolarDB数据库,实现百亿级数据的高效向量检索
阿里云瑶池PolarDB PostgreSQL版作为钉钉ONE的底层数据库,凭借分布式架构与向量检索能力,支撑百亿级数据、高并发与AI智能推荐,助力钉钉实现“事找人”的办公新范式。
|
26天前
|
SQL JSON 分布式计算
【跨国数仓迁移最佳实践6】MaxCompute SQL语法及函数功能增强,10万条SQL转写顺利迁移
本系列文章将围绕东南亚头部科技集团的真实迁移历程展开,逐步拆解 BigQuery 迁移至 MaxCompute 过程中的关键挑战与技术创新。本篇为第六篇,MaxCompute SQL语法及函数功能增强。 注:客户背景为东南亚头部科技集团,文中用 GoTerra 表示。
237 20