首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | 基础架构:一条SQL查询语句是如何执行的?
02 | 日志系统:一条SQL更新语句是如何执行的?
03 | 事务隔离:为什么你改了我还看不见?
04 | 深入浅出索引(上)
05 | 深入浅出索引(下)
06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?
07 | 行锁功过:怎么减少行锁对性能的影响?
08 | 事务到底是隔离的还是不隔离的?
09 | 普通索引和唯一索引,应该怎么选择?
10 | MySQL为什么有时候会选错索引?
11 | 怎么给字符串字段加索引?
12 | 为什么我的MySQL会“抖”一下?
13 | 为什么表数据删掉一半,表文件大小不变?
14 | count(*)这么慢,我该怎么办?
15 | 答疑文章(一):日志和索引相关问题
16 | “order by”是怎么工作的?
17 | 如何正确地显示随机消息?
18 | 为什么这些SQL语句逻辑相同,性能却差异巨大?
19 | 为什么我只查一行的语句,也执行这么慢?
20 | 幻读是什么,幻读有什么问题?
21 | 为什么我只改一行的语句,锁这么多?
22 | MySQL有哪些“饮鸩止渴”提高性能的方法?
23 | MySQL是怎么保证数据不丢的?
24 | MySQL是怎么保证主备一致的?
25 | MySQL是怎么保证高可用的?
26 | 备库为什么会延迟好几个小时?
27 | 主库出问题了,从库怎么办?
28 | 读写分离有哪些坑?
29 | 如何判断一个数据库是不是出问题了?
30 | 答疑文章(二):用动态的观点看加锁
31 | 误删数据后除了跑路,还能怎么办?
32 | 为什么还有kill不掉的语句?
33 | 我查这么多数据,会不会把数据库内存打爆?
34 | 到底可不可以使用join?
35 | join语句怎么优化?
36 | 为什么临时表可以重名?
37 | 什么时候会使用内部临时表?
38 | 都说InnoDB好,那还要不要使用Memory引擎?
39 | 自增主键为什么不是连续的?
40 | insert语句的锁为什么这么多?
41 | 怎么最快地复制一张表?
42 | grant之后要跟着flush privileges吗?
43 | 要不要使用分区表?
44 | 答疑文章(三):说一说这些好问题
45 | 自增id用完怎么办?
当前位置:
首页>>
技术小册>>
MySQL 实战 45 讲
小册名称:MySQL 实战 45 讲
### 10 | MySQL为什么有时候会选错索引? 在深入探讨MySQL为什么会“选错”索引之前,我们首先需要明确一点:MySQL的查询优化器(Query Optimizer)在选择索引时,是基于统计信息和成本估算来做出最优决策的。然而,由于数据分布、查询条件、系统状态等多种因素的影响,这种决策并不总是完美的,即所谓的“选错”索引现象便时有发生。本章节将详细解析这一现象背后的原因,并探讨如何减少或避免此类情况的发生。 #### 一、MySQL索引选择机制概述 MySQL的查询优化器在接收到SQL查询后,会进行一系列复杂的分析和计算,以决定如何高效地执行这个查询。这包括选择哪些表进行连接(JOIN)、以什么顺序连接这些表、以及是否使用索引以及如何使用索引等。在索引选择方面,MySQL会考虑多个因素,如索引的类型(如B-Tree、Hash等)、索引列的数据分布、索引的选择性(即索引列中唯一值的比例)、查询条件中的过滤条件等。 #### 二、选错索引的常见原因 ##### 1. **统计信息不准确** MySQL依赖统计信息来估算查询的成本,并据此选择索引。统计信息主要包括表的大小、行数、每列的唯一值数量等。如果这些统计信息过时或不准确(例如,在数据大量变动后未及时更新),优化器就可能做出不恰当的索引选择。 **解决策略**: - 定期执行`ANALYZE TABLE`命令来更新表的统计信息。 - 监控统计信息的更新频率,确保在数据变动较大时及时更新。 ##### 2. **查询条件复杂或不明确** 当查询条件包含多个列、使用了函数或表达式、或者涉及到复杂的逻辑判断时,优化器可能难以准确评估索引的有效性。例如,对索引列使用函数(如`UPPER(column)`)会阻止MySQL使用索引。 **解决策略**: - 简化查询条件,尽量避免在索引列上使用函数或复杂的表达式。 - 如果必须使用函数或表达式,考虑在查询前对数据进行预处理,或创建计算列并为其建立索引。 ##### 3. **索引选择性低** 如果索引列的值分布非常集中(即选择性低),那么使用该索引进行过滤的效果可能并不明显,甚至不如全表扫描。此时,优化器可能会错误地选择不使用索引。 **解决策略**: - 评估索引的选择性,确保索引列具有足够高的唯一值比例。 - 对于选择性较低的列,考虑与其他列组合创建复合索引,以提高索引的有效性。 ##### 4. **索引维护不当** 索引的维护状况也会影响其性能。例如,如果索引碎片化严重,或者索引页(Index Pages)中的空闲空间过多,都会导致索引查询效率下降。 **解决策略**: - 定期对索引进行重建或优化(如使用`OPTIMIZE TABLE`命令)。 - 监控索引的碎片化程度,并根据实际情况进行维护。 ##### 5. **成本估算误差** MySQL的优化器在估算查询成本时,会基于一系列的假设和简化。然而,在某些情况下,这些假设可能不成立,导致成本估算出现较大误差,从而选择错误的索引。 **解决策略**: - 使用`EXPLAIN`或`EXPLAIN ANALYZE`(MySQL 8.0+)查看查询的执行计划和成本估算,分析可能的误差来源。 - 根据实际情况调整查询或优化器设置,以减少成本估算误差。 #### 三、如何避免选错索引 ##### 1. **合理设计索引** 根据数据的查询模式和更新模式,合理设计索引。包括选择合适的索引类型、确定索引列、考虑创建复合索引等。 ##### 2. **监控和优化统计信息** 定期监控并更新表的统计信息,确保优化器能够基于准确的数据进行决策。 ##### 3. **优化查询语句** 编写高效的查询语句,避免在索引列上使用函数或复杂的表达式,尽量保持查询条件的简单和明确。 ##### 4. **使用索引提示** 在特定情况下,可以使用MySQL的索引提示(Index Hints)来强制优化器使用特定的索引。但这种方法应谨慎使用,因为它会绕过优化器的自动选择机制。 ##### 5. **分析和调整优化器设置** 了解并调整MySQL优化器的相关设置,如优化器类型(如`optimizer_switch`中的设置)、成本常量的值等,以适应不同的查询需求和数据特点。 #### 四、总结 MySQL在选择索引时,虽然会基于统计信息和成本估算做出最优决策,但由于多种因素的影响,仍有可能出现“选错”索引的情况。为了减少或避免此类现象的发生,我们需要从索引设计、统计信息更新、查询优化、索引维护等多个方面入手,综合运用各种策略和技术手段,提高查询效率和数据访问性能。同时,也需要保持对MySQL优化器行为的持续关注和学习,以便在遇到问题时能够迅速定位并解决。
上一篇:
09 | 普通索引和唯一索引,应该怎么选择?
下一篇:
11 | 怎么给字符串字段加索引?
该分类下的相关小册推荐:
MySQL从入门到精通(五)
细说MySQL(零基础到高级应用)
MySQL8.0入门与实践
MySQL从入门到精通(四)
MySQL从入门到精通(一)
MySQL从入门到精通(三)
MySQL必会核心问题
MySQL从入门到精通(二)
SQL零基础到熟练应用(增删改查)