如何监测MySQL是否命中索引?

本文深入解析MySQL的EXPLAIN命令,介绍如何通过SQL执行计划优化查询效率。文章详细解释了执行计划中的各项指标,如id、select_type、table、type等,并提供实例帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在日常工作中,我们有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,此时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。(QEP:sql生成一个执行计划query Execution plan)

mysql> explain select * from servers;
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | servers | ALL  | NULL          | NULL | NULL    | NULL |    1 | NULL  |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
1 row in set (0.03 sec)

expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra,下面对这些字段出现的可能进行解释:

一、 id

     我的理解是SQL执行的顺序的标识,SQL从大到小的执行

1. id相同时,执行顺序由上至下

2. 如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

3.id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行

二、select_type

      示查询中每个select子句的类型

(1) SIMPLE(简单SELECT,不使用UNION或子查询等)

(2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)

(3) UNION(UNION中的第二个或后面的SELECT语句)

(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)

(5) UNION RESULT(UNION的结果)

(6) SUBQUERY(子查询中的第一个SELECT)

(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)

(8) DERIVED(派生表的SELECT, FROM子句的子查询)

(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)

三、table

显示这一行的数据是关于哪张表的,有时不是真实的表名字,看到的是derivedx(x是个数字,我的理解是第几步执行的结果)

 

mysql> explain select * from (select * from ( select * from t1 where id=2602) a) b;
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
| id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
|  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |
|  2 | DERIVED     | <derived3> | system | NULL              | NULL    | NULL    | NULL |    1 |       |
|  3 | DERIVED     | t1         | const  | PRIMARY,idx_t1_id | PRIMARY | 4       |      |    1 |       |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------

四、type

表示MySQL在表中找到所需行的方式,又称“访问类型”。

常用的类型有: ALL, index,  range, ref, eq_ref, const, system, NULL(从左到右,性能从差到好)

ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行

index: Full Index Scan,index与ALL区别为index类型只遍历索引树

range:只检索给定范围的行,使用一个索引来选择行

ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件

const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system

NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

五、possible_keys

指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用

该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。
如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询

六、Key

key列显示MySQL实际决定使用的键(索引)

如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

七、key_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)

不损失精确性的情况下,长度越短越好 

八、ref

表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

九、rows

 表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数

十、Extra

该列包含MySQL解决查询的详细信息,有以下几种情况:

Using where:列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤

Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询

Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”

Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。

Impossible where:这个值强调了where语句会导致没有符合条件的行。

Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行

 

总结:
• EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
• EXPLAIN不考虑各种Cache
• EXPLAIN不能显示MySQL在执行查询时所作的优化工作
• 部分统计信息是估算的,并非精确值
• EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。

<think>好的,我现在需要解释MySQL中的“索引命中”、“索引回表”和“索引下推”这三个概念。首先,我得确保自己正确理解每个术语的含义,然后组织语言用中文清晰地表达出来,同时遵循用户提供的格式要求,比如行内公式用$...$,独立公式用$$...$$,并且结构要清晰。 首先,索引命中。这应该是指当执行查询时,MySQL能够利用索引来快速定位数据,而无需全表扫描。比如,如果有一个索引在name字段上,查询条件WHERE name = 'Alice'就会命中这个索引。需要说明索引的结构,比如B+树,以及如何通过索引快速查找数据行。 接下来是索引回表。当查询的列不在索引中时,即使命中索引MySQL还需要根据索引中的主键值回到主键索引(聚簇索引)中查找完整的行数据。这个过程称为回表。例如,索引是(name),但查询需要获取age,这时候就需要回表。这里可能需要提到覆盖索引的概念,即如果索引包含所有需要的字段,就可以避免回表。 然后是索引下推(Index Condition Pushdown,ICP)。这是在MySQL 5.6引入的优化技术,允许在存储引擎层提前过滤不符合条件的行,减少回表次数。比如,查询条件WHERE name LIKE 'A%' AND age > 20,如果索引在(name, age)上,在没有ICP的情况下,存储引擎会先找到所有name以A开头的主键,然后回表获取age再过滤。而有了ICP,存储引擎会直接在索引中检查age条件,减少回表的数据量。需要解释ICP的作用和如何提升性能。 接下来需要考虑如何将这些内容结构化,分点说明,每个部分可能还需要例子或场景说明。同时注意用户提到的格式要求,行内数学表达式比如索引结构可能需要用LaTeX,例如B+树的高度$h$,查找复杂度$O(\log n)$等。不过根据用户给的例子,可能不需要太复杂的公式,所以这里可能需要酌情处理。 需要检查是否有遗漏的关键点,比如索引的结构、回表的原因、覆盖索引、ICP的工作原理和版本支持。同时确保语言通俗易懂,避免技术术语堆砌,但又要准确。可能还需要对比有无ICP的情况下的执行流程差异,以突出其优化效果。 最后,确保回答符合用户的结构要求:分点解释每个概念,可能包括定义、原理、示例、影响或优化建议。同时使用中文,避免Markdown格式,但保持段落清晰,可能用序号或标题来分隔各个部分。同时注意LaTeX的正确使用,比如行内公式用$...$,独立公式如果需要的话用$$...$$,但根据用户的问题,可能不需要太多公式,主要是在解释索引结构或查询过程时可能需要。 总结一下,回答的结构大致如下: 1. 索引命中 - 定义:查询条件使用索引快速定位数据 - 原理:B+树结构,减少扫描行数 - 示例:WHERE子句使用索引列 - 注意点:最左前缀原则,索引选择性 2. 索引回表 - 定义:需要回主键索引取数据 - 原理:二级索引存储主键值 - 示例:查询列不在索引中 - 优化:覆盖索引 3. 索引下推 - 定义:存储引擎层提前过滤 - 原理:在索引遍历时应用WHERE条件 - 示例:组合索引,部分条件在索引中处理 - 优势:减少回表次数,提升性能 在写作过程中,需要检查每个部分是否准确,是否有错误。例如,索引下推是否仅适用于组合索引,还是单列索引也可以?实际上,ICP适用于索引能够覆盖的列,不管是否是组合索引,但通常组合索引更能体现其优势。另外,需要确认MySQL版本支持情况,ICP从5.6开始支持。 可能还需要提到执行计划中的Using index condition来表示ICP的使用,而Using index表示覆盖索引。这些细节能帮助用户更好地理解如何诊断和优化查询。 最后,确保语言流畅,逻辑清晰,符合用户的要求,分点讲解,帮助用户逐步理解这三个概念。</think>### MySQL索引命中索引回表、索引下推详解 #### 一、索引命中 1. **定义** 当查询条件**完全或部分匹配索引结构**时,MySQL可通过索引快速定位数据,避免全表扫描。例如: ```sql SELECT * FROM users WHERE name = 'Alice'; -- 若name字段有索引,则命中 ``` 2. **原理** - 索引通常采用$B^+$树结构,树高$h$决定查询复杂度为$O(\log n)$。 - **最左前缀原则**:联合索引$(a, b, c)$只能按$a$ → $a+b$ → $a+b+c$的顺序使用。 - **索引选择性**:唯一性高的字段(如ID)更适合建索引。 3. **示例** - 命中:`WHERE a=1 AND b=2`(联合索引$(a,b)$) - 未命中:`WHERE b=2`(未从最左字段$a$开始) --- #### 二、索引回表 1. **定义** 当索引**未覆盖查询所需全部列**时,需根据索引中的主键值**回主键索引(聚簇索引)**获取完整行数据。 2. **原理** - 二级索引(如`INDEX(name)`)仅存储主键值。 - 若查询需获取`age`字段(未包含在索引中),流程如下: ```sql 1. 通过二级索引找到name='Alice'对应的主键id=100 2. 回主键索引查找id=100的行,获取age=25 ``` 3. **优化:覆盖索引** 将查询列全部加入索引,例如: ```sql CREATE INDEX idx_name_age ON users(name, age); SELECT age FROM users WHERE name = 'Alice'; -- 无需回表 ``` --- #### 三、索引下推(ICP,Index Condition Pushdown) 1. **定义** MySQL 5.6+引入的优化技术,**将WHERE条件过滤提前到存储引擎层执行**,减少回表次数。 2. **原理** - **无ICP**:存储引擎仅按索引最左前缀筛选数据,剩余条件由Server层处理。 - **有ICP**:存储引擎直接利用索引中的字段过滤数据,减少传递给Server层的数据量。 3. **示例** ```sql -- 表结构:INDEX(name, age) SELECT * FROM users WHERE name LIKE 'A%' AND age > 20; ``` - **无ICP**:先找到所有`name LIKE 'A%'`的主键,回表后由Server层过滤`age > 20`。 - **有ICP**:存储引擎在索引中直接过滤`name LIKE 'A%' AND age > 20`,仅回表符合条件的主键。 4. **优势** - 减少回表次数,降低I/O开销。 - 执行计划显示`Using index condition`即表示触发ICP。 --- ### 总结对比 | 概念 | 触发场景 | 优化目标 | 关键标志 | |------------|------------------------------|-------------------|-----------------------| | 索引命中 | 查询条件匹配索引结构 | 减少扫描行数 | `Using index` | | 索引回表 | 查询列未完全被索引覆盖 | 避免回表 | 无 | | 索引下推 | WHERE条件可被索引部分覆盖 | 减少回表次数 | `Using index condition` | 通过合理设计索引(如覆盖索引、联合索引)和利用ICP,可显著提升查询性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值