Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL慢查询排查指南

MySQL慢查询从定位问题到EXPLAIN的排查指南

作者:西凉的悲伤

在 Java 后端开发中,数据库慢查询是非常常见的性能问题,本文从Java后端实际场景出发,教你一步步定位慢SQL、分析EXPLAIN执行计划,并给出索引优化和SQL改写建议,帮你快速解决接口响应慢、订单查询卡顿等问题,需要的朋友可以参考下

前言

在 Java 后端开发中,数据库慢查询是非常常见的性能问题。例如,接口原本几十毫秒就能返回,突然变成几秒;订单列表查询很慢;分页越往后越慢;或者 SQL 明明建立了索引,却依然执行缓慢。

要系统地排查慢查询,需要掌握两件事:

  1. 如何定位慢 SQL,并判断慢在哪里。
  2. 如何通过 EXPLAIN 理解 SQL 的执行计划,找到可能的性能瓶颈。

本文以 MySQL 8.0 + InnoDB 为主,结合企业订单、员工列表等 Java 后端业务场景,详细解释排查流程,以及 EXPLAIN 各列的含义、常见值和判断方法。

一、什么是慢查询?

慢查询通常指执行时间超过某个阈值的 SQL。

例如,某个系统把执行时间超过 1 秒的 SQL 记录为慢查询:

SELECT *
FROM car_order
WHERE company_id = 1001
ORDER BY create_time DESC
LIMIT 20;

但要注意,慢查询不等于 SQL 一定没有使用索引。

即使 SQL 使用了索引,也可能因为以下原因变慢:

因此,排查时不能只看 SQL,也不能只看索引,而应该从应用到数据库逐层分析。

二、慢查询排查的完整流程

推荐按照下面的顺序排查。

定位慢 SQL

从应用日志、APM、数据库慢查询日志中,找到具体 SQL、执行时间、参数和调用频率。

判断耗时发生在哪一层

区分 SQL 执行、锁等待、连接池等待、网络传输和 Java 业务处理。

查看表结构和索引

执行 SHOW CREATE TABLE、SHOW INDEX,确认索引是否存在、字段顺序是否合理。

使用 EXPLAIN 分析执行计划

重点看 type、possible_keys、key、key_len、rows、filtered、Extra。

检查实际执行情况

在合适环境下使用 EXPLAIN ANALYZE,对比估算行数和实际行数、各步骤耗时。

优化并验证

调整 SQL、索引、分页方式或事务设计,然后在可比较的条件下验证性能改善。

一个非常重要的原则是:先定位,再分析,再优化,最后验证。不要一看到 SQL 慢就盲目增加索引。

2.1 第一步:确认慢 SQL 是什么

在 Java 项目中,可以从以下地方定位:

需要收集的信息包括:

信息作用
SQL 文本确认查询逻辑
参数值判断数据分布和执行计划差异
执行耗时判断问题严重程度
调用频率区分单次慢与高频累积开销
返回行数判断结果集是否过大
表的数据量判断扫描规模
并发情况判断是否与资源竞争有关

例如,同一条 SQL:

SELECT *
FROM car_order
WHERE company_id = ?
  AND status = ?;

当参数为某个小企业时,可能只返回 10 条记录;当参数为大型企业时,可能返回 30 万条记录。

SQL 文本完全相同,执行时间却可能差异很大。因此,排查时要关注真实参数,而不只是 SQL 模板。

2.2 第二步:开启和检查 MySQL 慢查询日志

先查看相关配置:

SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
SHOW VARIABLES LIKE 'slow_query_log_file';
SHOW VARIABLES LIKE 'log_output';

主要关注:

如果当前实例允许修改配置,可以在评估后启用:

SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;

这里设置的阈值是 1 秒,仅作为示例。

注意:SET GLOBAL 修改的是运行中的全局变量,具体是否立即影响现有连接、是否持久化,以及重启后的行为,需要根据变量属性和 MySQL 版本确认。生产环境应该通过统一配置管理实施变更,而不是直接随意修改。

慢查询日志也不一定记录所有高频但单次较快的 SQL。例如,一条 SQL 每次只耗时 50 毫秒,但每秒执行数千次,依然可能是重要的性能瓶颈。

2.3 第三步:先排除锁等待与资源问题

有些 SQL 看起来执行了很久,实际上并不是索引查找慢,而是在等待其他事务释放锁。

可以先查看当前活动:

SHOW FULL PROCESSLIST;

重点关注:

例如,如果发现某条查询长时间处于锁等待相关状态,就要继续检查事务、锁和阻塞链,而不是直接修改索引。

如果怀疑 InnoDB 锁问题,还可以检查:

SHOW ENGINE INNODB STATUS;

此外,还应结合数据库监控查看 CPU、磁盘 I/O、连接数、Buffer Pool 命中情况等。

三、EXPLAIN 到底是什么?

EXPLAIN 是 MySQL 提供的执行计划分析工具,可以让我们了解数据库准备如何执行一条 SQL。

例如:

EXPLAIN
SELECT id, order_no, amount
FROM car_order
WHERE company_id = 1001
  AND status = 1
ORDER BY create_time DESC
LIMIT 20;

对于常规的表格输出,MySQL 8.0 的 EXPLAIN 通常包含以下 12 列:

列名中文含义重点程度
id查询块的标识一般
select_type查询类型一般
table当前分析的表或派生表一般
partitions命中的分区分区表重点关注
type表的访问方式非常重要
possible_keys可能使用的索引重要
key实际选择的索引非常重要
key_len使用的索引键长度重要
ref与索引进行比较的列或常量重要
rows预计检查的行数非常重要
filtered预计经过表条件过滤后保留的比例重要
Extra其他执行信息非常重要

要注意:一条 SQL 如果涉及多张表,EXPLAIN 通常会为每张参与执行的表输出一行。复杂 SQL 还可能包含子查询、派生表等对应的执行计划信息。

下面逐列讲解,并重点说明每列可能出现的值。

四、EXPLAIN 各列详细解析

4.1id:查询块标识

id 表示查询中 SELECT 查询块的标识。

例如:

EXPLAIN
SELECT *
FROM car_order
WHERE id = 1001;

可能得到:

idselect_typetabletypekey
1SIMPLEcar_orderconstPRIMARY

这里的 id = 1 表示这是一个简单查询中的查询块。

再看一个子查询:

EXPLAIN
SELECT *
FROM car_order
WHERE company_id IN (
    SELECT id
    FROM company
    WHERE status = 1
);

这个查询可能会被优化器改写,例如转换为半连接,所以不能保证一定出现两个不同的 id。

id的值怎么看?

注意:不要简单认为 id 越大就越慢,也不要认为必须严格按照 id 从小到大执行。 复杂 SQL 的实际执行顺序要结合 select_type、表访问顺序和完整执行计划分析。

4.2select_type:查询类型

该列用于描述当前查询块属于哪种查询结构。

常见值如下:

值含义示例或说明
SIMPLE简单查询块没有子查询或 UNION 的简单 SELECT
PRIMARY最外层查询块复杂查询中的最外层 SELECT
SUBQUERY非关联子查询子查询不依赖外层查询的当前行
DEPENDENT SUBQUERY依赖外层查询的子查询子查询引用外层字段
DERIVED派生表FROM (SELECT ...) t
UNIONUNION 中非第一个查询块多个查询结果合并
UNION RESULTUNION 的结果集合表示合并后的结果
MATERIALIZED物化子查询结果优化器将子查询结果物化后使用
DEPENDENT UNION依赖外层查询的 UNION 分支复杂子查询场景

例如:

SELECT *
FROM (
    SELECT company_id, COUNT(*) AS total
    FROM car_order
    GROUP BY company_id
) t
WHERE t.total > 10;

内部的 SELECT 可能显示为 DERIVED,外部查询可能显示为 PRIMARY。

哪些值需要重点关注?

如果看到:

DEPENDENT SUBQUERY

建议检查是否存在关联子查询重复执行的成本。例如:

SELECT *
FROM company c
WHERE EXISTS (
    SELECT 1
    FROM car_order o
    WHERE o.company_id = c.id
);

这里子查询引用了外层的 c.id。不过,MySQL 可能对 EXISTS 进行半连接等优化,因此出现依赖子查询并不一定意味着性能差。

如果看到 DERIVED,也不代表一定有问题。应该进一步判断派生表是否需要物化、数据量有多大,以及是否可以通过其他 SQL 写法改善执行计划。

4.3table:当前分析的表

该列显示执行计划当前处理的表、表别名或派生表。

例如:

SELECT o.id, c.company_name
FROM car_order o
JOIN company c ON o.company_id = c.id;

执行计划可能出现:

table含义
o订单表的别名
c企业表的别名

如果 SQL 中使用了:

FROM (SELECT ...) t

那么 table 也可能显示为 t 或其他派生表标识。

如何利用这一列?

如果 SQL 涉及多张表,可以先识别每一行对应哪张表,再查看它的 type、key 和 rows。

尤其是多表 JOIN,需要关注:

4.4partitions:命中的分区

如果表采用了分区,例如按月份对订单进行分区,那么 partitions 会显示查询可能访问的分区。

例如:

SELECT *
FROM car_order
WHERE create_time >= '2026-10-01'
  AND create_time <  '2026-11-01';

如果表按时间分区,并且优化器能够根据条件裁剪分区,结果可能类似:

partitions
p202610

这里仅作示意,p202610 是假设的分区名。

常见情况:

如果按月分区的表查询某个月的数据,却需要扫描大量月份的分区,就应该检查分区键、查询条件以及分区裁剪是否生效。

但要注意,分区不能替代索引。分区主要帮助缩小需要访问的数据分区,分区内部仍然可能需要全表扫描或使用索引。

4.5type:访问方式——最重要的字段之一

type 表示 MySQL 访问当前表时使用的访问方式。官方文档中对应的 JSON 字段名为 access_type。

这是判断执行计划是否存在潜在问题的重要字段。

常见值包括:

type含义一般判断
system特殊的单行系统表访问通常开销很低
const通过主键或唯一索引等值查找,至多一行通常非常高效
eq_refJOIN 中使用主键或唯一非空索引匹配一行通常高效
ref通过非唯一索引进行等值匹配常见且通常合理
fulltext使用全文索引访问取决于搜索场景
ref_or_null通过索引查找指定值,同时查找 NULL取决于查询
index_merge合并多个索引的访问结果需结合具体计划
unique_subquery某些 IN 子查询优化后的唯一索引访问通常较高效
index_subquery某些 IN 子查询通过索引查找需结合具体计划
range索引范围扫描常见且通常合理
index全索引扫描需要判断扫描规模
ALL全表扫描大表慢查询中重点排查

不同版本和执行计划可能出现其他值,例如 hash_join 相关信息在 MySQL 8.0 中主要通过 FORMAT=TREE 展示,而不是传统表格的 type 列。

①const:常量级查找

例如:

SELECT *
FROM car_order
WHERE id = 1001;

如果 id 是主键,可能出现:

type = const
key  = PRIMARY
rows = 1

对于唯一索引的等值查询,如果条件保证最多匹配一条记录,也可能出现类似的访问方式。

②eq_ref:关联查询中的高效访问

例如:

SELECT o.id, c.company_name
FROM car_order o
JOIN company c ON o.company_id = c.id;

如果 company.id 是主键,执行 JOIN 时可能通过主键为每个订单匹配唯一的一条企业记录,company 对应的访问方式就可能是 eq_ref。

③ref:普通索引等值查询

假设:

CREATE INDEX idx_car_order_company
ON car_order (company_id);

执行:

SELECT *
FROM car_order
WHERE company_id = 1001;

可能出现:

type = ref
key  = idx_car_order_company

因为同一个企业可能有多条订单记录,所以这里不是唯一索引的单行查找。

ref 很常见,不代表 SQL 有问题。

④range:范围扫描

例如:

SELECT *
FROM car_order
WHERE create_time >= '2026-10-01'
  AND create_time <  '2026-11-01';

如果存在:

CREATE INDEX idx_car_order_create_time
ON car_order (create_time);

可能出现:

type = range
key  = idx_car_order_create_time

这意味着数据库利用索引查找指定范围的数据。

range 经常出现在日期范围、数值范围和部分 IN 查询中。

⑤index:扫描整个索引

例如:

SELECT create_time
FROM car_order;

如果某个索引包含 create_time,优化器可能选择扫描整个索引来返回数据。

这种方式可能比扫描完整数据行更省空间,但它仍然可能扫描大量索引记录。

因此:

index 不等于“查询很快”,也不等于“只扫描了一条索引记录”。

⑥ALL:全表扫描

例如:

SELECT *
FROM car_order
WHERE remark = 'test';

如果 remark 没有合适的索引,可能出现:

type = ALL
key  = NULL

这意味着执行计划选择全表扫描。

但也不能仅凭 ALL 就认定 SQL 有问题。如果表很小,或者查询需要返回表中绝大多数记录,全表扫描可能是更合理的方案。

实际排查重点是:大表、低选择性过滤、扫描行数巨大、接口耗时高的 ALL。

4.6possible_keys:可能使用的索引

该列列出优化器认为有可能用于当前表访问的索引。

例如:

SELECT *
FROM car_order
WHERE company_id = 1001
  AND status = 1;

如果存在:

CREATE INDEX idx_company
ON car_order (company_id);

CREATE INDEX idx_status
ON car_order (status);

CREATE INDEX idx_company_status
ON car_order (company_id, status);

执行计划中的 possible_keys 可能显示:

idx_company,idx_status,idx_company_status

这里要注意两个问题。

第一,possible_keys 不等于最终使用的索引。

优化器可能考虑多个索引,最终选择其中一个,也可能认为全表扫描更划算。

第二,possible_keys = NULL 不一定代表数据库完全没有索引。

例如,查询条件没有使用可用于定位数据的索引列,或者优化器认为现有索引不适合当前访问方式,就可能出现 NULL。

排查建议

如果你认为 SQL 应该使用某个索引,但 possible_keys 中没有它,可以检查:

4.7key:实际使用的索引

这是最值得关注的字段之一。

假设:

CREATE INDEX idx_company_status
ON car_order (company_id, status);

执行:

EXPLAIN
SELECT *
FROM car_order
WHERE company_id = 1001
  AND status = 1;

可能得到:

possible_keys = idx_company_status
key           = idx_company_status

说明优化器选择了这个联合索引。

常见值:

key 的值含义
PRIMARY使用主键索引
idx_company_status使用指定的普通或联合索引
uk_order_no使用指定的唯一索引
NULL没有选择索引作为当前访问路径

key = NULL应该怎么办?

不要直接使用 FORCE INDEX 强制指定索引。

建议先检查:

  1. 表的数据量是否很小。
  2. 查询是否返回大部分记录。
  3. possible_keys 是否为空。
  4. 索引字段顺序是否与查询条件匹配。
  5. 索引统计信息是否准确。
  6. 是否存在函数、类型转换或其他不利于索引范围访问的写法。

只有经过测试,确认优化器选择不合理,并且强制索引在代表性数据上确实更优,才考虑索引提示等手段。

4.8key_len:实际使用的索引键长度

key_len 表示执行计划使用的索引键长度,单位通常是字节。

它是分析联合索引时非常有价值的字段,因为可以帮助判断索引的哪些部分参与了定位。

假设:

CREATE TABLE demo_order (
    id BIGINT NOT NULL PRIMARY KEY,
    company_id BIGINT NOT NULL,
    status TINYINT NOT NULL,
    create_time DATETIME NOT NULL
);

创建索引:

CREATE INDEX idx_company_status_time
ON demo_order (company_id, status, create_time);

字段的大致存储长度:

字段类型常见索引键长度
company_idBIGINT NOT NULL8 字节
statusTINYINT NOT NULL1 字节
create_timeDATETIME NOT NULL5 字节

在这个示例中,如果执行计划实际使用了前两列,key_len 可能是 9;如果三个字段均参与使用,可能是 14。

这只是简化示例,实际值还会受到字段定义、可空性、字符集、变长字段长度编码等因素影响。VARCHAR 字段还需要考虑字符集的最大字节数以及长度存储信息。

如何通过key_len判断联合索引使用情况?

假设索引为:

(company_id, status, create_time)

分别执行:

-- 查询一
WHERE company_id = 1001;

-- 查询二
WHERE company_id = 1001
  AND status = 1;

-- 查询三
WHERE company_id = 1001
  AND status = 1
  AND create_time >= '2026-10-01';

如果字段定义符合前面的示例,并且执行计划使用对应的索引前缀,那么 key_len 可能依次显示:

8
9
14

不过,不能机械地用 key_len 推断所有联合索引列是否被用于精确定位,因为范围条件、可空字段和索引访问细节都会影响结果。

最重要的是结合 key、key_len、ref 和实际 SQL 一起判断。

4.9ref:索引查找使用的比较对象

ref 表示数据库使用什么值或字段,与 key 对应的索引键进行比较。

例如:

SELECT *
FROM car_order
WHERE company_id = 1001;

如果使用 idx_company,ref 可能显示:

const

表示使用常量进行匹配。

对于 JOIN:

SELECT o.id, c.company_name
FROM car_order o
JOIN company c ON o.company_id = c.id;

访问 company 表时,ref 可能显示:

db.o.company_id

具体格式取决于数据库及执行计划的显示方式。

常见值包括:

ref 的值含义
const使用常量匹配索引
db.table.column使用另一张表的列匹配索引
func使用函数或表达式结果匹配索引
NULL当前访问方式没有对应的比较引用,或不适用

如果看到 func,可以进一步执行:

SHOW WARNINGS;

结合扩展执行计划信息,检查比较条件是否涉及函数、运算表达式或类型转换。

4.10rows:预计需要检查多少行

这是判断扫描规模的核心字段之一。

假设执行计划显示:

type = ref
rows = 500000

意味着优化器预计需要检查大约 50 万行。

虽然它选择了索引,但预计检查的数据量依然很大。

这可能是查询慢的原因之一。

rows具体代表什么?

它是优化器估算的、执行当前表访问预计需要检查的行数,而不是最终返回给应用程序的行数。

例如:

SELECT *
FROM car_order
WHERE company_id = 1001
  AND status = 1;

假设某个企业共有 50 万条订单,其中只有 100 条状态为 1。

如果执行计划使用 (company_id) 索引,再通过其他条件过滤,可能预计检查大量记录,最后只返回少量结果。

如果存在更匹配的联合索引:

CREATE INDEX idx_company_status
ON car_order (company_id, status);

优化器就可能直接缩小索引查找范围,减少需要检查的记录。

但需要强调,rows 是估算值,尤其在 InnoDB 中并不保证准确。

如何判断rows是否过大?

不能只看一个固定阈值,而应该结合表的数据量和查询结果判断。

例如:

预计 rows实际返回行数初步判断
11单行查找,通常较理想
10080可能比较合理
10000020需要检查过滤效率
1000000800000可能本来就需要读取大量数据

如果预计扫描 10 万行,最终只返回 20 行,就值得进一步检查索引设计、过滤条件和实际执行情况。

不过,对于覆盖索引、索引条件下推、范围扫描等不同访问方式,扫描行数的具体含义会有差异,不能只靠这个字段下结论。

4.11filtered:预计过滤比例

filtered 表示预计经过当前表的相关过滤条件后,保留下来的行所占的百分比。

例如:

rows     = 100000
filtered = 1.00

意思是优化器估计访问阶段涉及约 100000 行,经过相应的表条件过滤后,保留比例约为 1%。

估算保留行数为:

如果是 JOIN 查询,这个估算结果有助于理解后续表需要处理多少匹配行。官方文档也通过 rows × filtered 说明这一估算关系。

常见值:

注意,filtered 越低不一定代表 SQL 越慢。

例如,索引扫描 1000 行,最终只保留 10 行,过滤效率可能很好;但如果扫描 100 万行,最后也只保留 10 行,那么扫描范围就可能过大。

因此,建议将 rows 和 filtered 结合起来看。

4.12Extra:额外执行信息

Extra 是非常重要的一列,它会告诉你数据库在普通访问方式之外,还需要进行哪些操作。

常见值如下:

Extra 值含义排查建议
Using index通常表示覆盖索引通常是有利信号
Using where需要通过条件进一步过滤本身不代表问题
Using index condition使用索引条件下推(ICP)可能减少回表
Using filesort需要额外排序检查排序字段和索引
Using temporary使用临时表处理部分操作检查分组、去重和排序
Using index for group-by利用索引优化分组或聚合通常是有利信号
Using join buffer使用连接缓冲区检查 JOIN 条件和索引
Impossible WHERE优化器判断条件不可能成立检查查询条件
Using intersect(...)使用多个索引结果的交集结合实际访问计划判断
Using union(...)使用多个索引结果的并集结合实际访问计划判断

这些信息可能组合出现,例如:

Using index condition; Using where

具体显示内容会因 MySQL 版本、查询类型和执行计划而有所不同。

①Using index

例如:

SELECT company_id, status
FROM car_order
WHERE company_id = 1001;

如果索引覆盖了查询需要的字段,就可能出现 Using index。

它通常意味着可以直接从索引中获得所需数据,不需要为了读取其他列再回表。

②Using where

例如:

SELECT *
FROM car_order
WHERE status = 1;

即使数据库使用某个索引,也可能还需要通过 WHERE 条件进一步过滤记录。

Using where 是正常的执行信息,不代表索引失效。

③Using index condition

这通常表示使用了索引条件下推(Index Condition Pushdown,ICP)。

它允许存储引擎利用索引中的字段先判断部分条件,尽可能减少需要回表读取的记录。

例如:

CREATE INDEX idx_company_status
ON car_order (company_id, status);

查询:

SELECT *
FROM car_order
WHERE company_id = 1001
  AND status > 1;

在适合的执行计划下,可能利用索引条件下推减少回表。

④Using filesort

例如:

SELECT *
FROM car_order
WHERE company_id = 1001
ORDER BY amount DESC
LIMIT 20;

如果没有合适的索引支持该排序,MySQL 可能需要执行额外排序,并显示 Using filesort。

可以考虑是否存在合理的索引:

CREATE INDEX idx_company_amount
ON car_order (company_id, amount);

但需要结合实际查询的选择性、返回行数、索引维护成本和排序方向验证。

另外,filesort 是 MySQL 对额外排序过程的术语,不意味着一定发生了磁盘文件排序。数据量较小时,排序可能在内存中完成。

⑤Using temporary

它表示执行计划使用了临时表处理某些操作。

例如:

SELECT status, COUNT(*)
FROM car_order
GROUP BY status
ORDER BY COUNT(*) DESC;

可能因为分组、聚合、排序等操作使用临时表。

看到它时,应该进一步判断:

不要仅仅为了消除 Using temporary 就随意增加索引,因为并非所有临时表都能或都值得通过索引消除。

五、把 EXPLAIN 的所有列放在一起分析

前面分别解释了 12 列,接下来用一个完整的案例,把这些字段串起来。

假设订单表已经建立以下索引:

CREATE INDEX idx_company_status_time
ON car_order (company_id, status, create_time);

查询:

EXPLAIN
SELECT id, company_id, status, create_time
FROM car_order
WHERE company_id = 1001
  AND status = 1
  AND create_time >= '2026-10-01'
  AND create_time < '2026-11-01'
ORDER BY create_time DESC
LIMIT 20;

下面是一份用于说明各列含义的模拟执行计划:

列名模拟值
id1
select_typeSIMPLE
tablecar_order
partitionsNULL
typerange
possible_keysidx_company_status_time
keyidx_company_status_time
key_len14
refNULL
rows500
filtered100.00
ExtraUsing where; Using index

以上数据是假设的示例,不代表在任何实际数据库中运行都会得到这些值。

5.1 如何解读这个执行计划?

第一步,看 type:

type = range

说明数据库采用索引范围扫描,而不是全表扫描。

第二步,看 key:

key = idx_company_status_time

说明优化器选择了预期的联合索引。

第三步,看 key_len:

key_len = 14

在前面假设的字段定义下,这可能意味着三个索引字段都参与了访问,但还要结合具体字段类型和范围条件确认。

第四步,看 rows:

rows = 500

优化器预计需要检查约 500 行。对于一张有数百万条记录的订单表,这可能是一个合理的扫描规模,但仍然需要与实际返回行数和真实耗时对比。

第五步,看 filtered:

filtered = 100.00

表示优化器预计保留比例为 100%。这并不是说整个表没有过滤,而是针对当前执行计划中该表访问和相关过滤阶段的估算。

第六步,看 Extra:

Using where; Using index

这里可以理解为需要通过条件过滤,并且查询可能被索引覆盖,不需要回表读取完整记录。

整体判断:这个执行计划看起来比较合理,但不能只靠 EXPLAIN 就断定 SQL 一定很快。 还需要看真实执行时间、实际扫描行数、并发和数据分布。

六、EXPLAIN ANALYZE:查看实际执行情况

普通 EXPLAIN 主要展示优化器的估算结果。MySQL 8.0.18 及以上版本提供了 EXPLAIN ANALYZE,可以实际执行查询并

以上就是MySQL慢查询从定位问题到EXPLAIN的排查指南的详细内容,更多关于MySQL慢查询排查指南的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文