找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3767

积分

0

好友

529

主题
发表于 11 小时前 | 查看: 2| 回复: 0

当数据库查询变慢时,你首先会想到什么命令?是EXPLAIN,还是去查看慢日志?掌握正确的性能分析命令,是每位后端工程师和DBA的必修课。今天,我们就来盘点几个在MySQL日常开发和故障排查中必备的性能分析命令,它们将帮助你快速定位SQL瓶颈。

MySQL常用性能分析命令思维导图

1. explain:洞察SQL执行计划

在MySQL调优中,EXPLAIN绝对是我们的首选工具。它的使用非常简单,只需在待分析的SQL语句前加上这个关键字,MySQL便会展示其预估的执行计划。

explain sql语句;
-- 例如:
explain select * from t_user;

执行后的结果通常如下:

mysql> explain select * from t_user;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    7 |   100.00 | NULL  |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

面对这一堆字段,我们该如何解读?以下是关键字段的含义解析:

  • id: 查询的序列号。如果是简单的单表查询,通常为1。如果存在子查询或嵌套查询,你会看到多个id,数字越大,执行优先级越高。
  • select_type: SIMPLE 代表这是一个不包含子查询或UNION的简单查询。
  • table: 显示查询涉及的表名。
  • type: 这是需要重点关注的字段之一。它显示了访问类型,从最优到最差大致是:system > const > eq_ref > ref > range > index > ALL。上面例子中的 ALL 意味着“全表扫描”,在数据量大时是主要的性能瓶颈。
  • possible_keys: MySQL认为可能适用于此查询的索引。例子中为NULL,表示没有找到可用的索引。
  • key: MySQL实际决定使用的索引。如果为NULL,则表示未使用索引。
  • rows: MySQL预估为了找到所需行而必须检查的行数。这是一个估算值,但值越大通常意味着查询成本越高。
  • Extra: 包含MySQL解决查询的额外信息。例如Using filesort(使用文件排序)、Using temporary(使用临时表)等都可能是性能问题的信号。

在日常分析中,我们不必纠结于每个字段,重点观察 typekeyrows 以及 Extra 字段,就足以判断一条SQL的大致性能表现。

2. analyze:修正索引统计信息

你是否遇到过MySQL“选错索引”的情况?这往往是由于索引的统计信息不准确,导致优化器对查询代价做出了错误预估。ANALYZE TABLE命令可以重新收集表的统计信息。

为什么会不准?
EXPLAIN中输出的rows(扫描行数)是一个基于统计信息的估计值。如果这个估计值与实际情况偏差很大,就可能导致优化器选择非最优的索引。

analyze table 表名;
-- 例如:
analyze table t_user;

执行后,如果返回状态为OK,则说明统计信息已更新。

mysql> analyze table t_user;
+-----------------+---------+----------+----------+
| Table           | Op      | Msg_type | Msg_text |
+-----------------+---------+----------+----------+
| testdb.t_user   | analyze | status   | OK       |
+-----------------+---------+----------+----------+
1 row in set (0.04 sec)

执行完ANALYZE后,再次运行EXPLAIN,MySQL会基于最新的、更准确的统计信息重新选择索引,很多“索引莫名失效”的问题由此得以解决。

当然,MySQL选错索引也可能是因为SQL语句本身的问题,例如对索引字段做了函数操作、发生了隐式类型转换或字符编码转换等。

3. show index:查看表索引结构

进行性能分析时,了解表上到底建立了哪些索引是基础。SHOW INDEX命令可以清晰展示一张表的索引详情。

show index from 表名;
-- 例如:
show index from t_user;

命令输出包含大量信息,我们关注几个核心字段:

mysql> show index from t_user;
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table  | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| t_user |          0 | PRIMARY   |            1 | id          | A         |           7 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| t_user |          1 | idx_phone |            1 | phone       | A         |           7 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
  • Key_name: 索引名称。PRIMARY代表主键索引。
  • Non_unique: 0表示唯一索引,1表示普通索引(允许重复值)。
  • Column_name: 构成索引的列名。
  • Seq_in_index: 该列在联合索引中的位置(从1开始)。这个顺序至关重要,它决定了联合索引是否能被最左前缀匹配规则命中。
  • Cardinality: 基数,即该列中不重复值的预估数量。这个值越大,说明该列的区分度越高,建立索引的效果通常越好。如果基数非常低(例如“性别”字段),建索引的意义就不大。
  • Index_type: 索引类型,InnoDB存储引擎默认都是BTREE

提示Cardinality是一个采样估算值,并非精确值,ANALYZE TABLE可以更新它。

4. show processlist:实时监控数据库连接

当数据库突然变慢,感觉有SQL“卡住”时,第一时间就应该运行SHOW PROCESSLIST。它能帮你查看当前数据库中的所有连接及其正在执行的操作。

show processlist;

输出结果如下,我们可以快速定位异常:

mysql> show processlist;
+----+-----------------+------------------+----------+---------+------+------------------------+------------------+
| Id | User            | Host             | db       | Command | Time | State                  | Info             |
+----+-----------------+------------------+----------+---------+------+------------------------+------------------+
|  5 | event_scheduler | localhost        | NULL     | Daemon  | 3508 | Waiting on empty queue | NULL             |
|  9 | root            | 127.0.0.1:43610  | testdb   | Query   |    0 | init                   | show processlist |
| 10 | root            | 172.17.0.1:52642 | NULL     | Sleep   | 3205 |                        | NULL             |
+----+-----------------+------------------+----------+---------+------+------------------------+------------------+

关键字段解读:

  • Id: 连接的标识符。如果想终止某个连接,可以使用 KILL Id 命令。
  • User/Host: 连接使用的用户名和客户端地址,有助于追踪问题来源。
  • Command: 当前连接执行的命令类型,常见的有Query(正在执行查询)、Sleep(连接空闲)。
  • Time: 这是需要重点关注的字段。表示该命令已经执行了多长时间(秒)。如果某条SQL的Time值异常大,说明它可能已经运行了很长时间,需要重点审查。
  • State: 连接当前状态,例如Sending dataLocked等。如果看到大量Locked,可能意味着存在锁等待问题。
  • Info: 正在执行的SQL语句(可能会被截断)。想看完整语句可以使用 SHOW FULL PROCESSLIST

5. 慢查询日志 (Slow Log):捕获系统所有慢SQL

前面的命令需要我们主动去排查特定的SQL。若要系统性地、被动地捕获所有执行缓慢的SQL,就必须依赖慢查询日志

第一步:查看当前慢查询配置

show variables like '%slow_query%';
show variables like 'long_query_time';

输出示例:

mysql> show variables like '%slow_query%';
+---------------------+--------------------------------------+
| Variable_name       | Value                                |
+---------------------+--------------------------------------+
| slow_query_log      | OFF                                  |
| slow_query_log_file | /var/lib/mysql/2be4983ea86a-slow.log |
+---------------------+--------------------------------------+

mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
  • slow_query_log: 是否开启慢查询日志(ON/OFF)。
  • slow_query_log_file: 慢查询日志文件的存储路径。
  • long_query_time: 定义“慢”的阈值,执行时间超过此值(秒)的SQL会被记录。默认10秒,生产环境通常调整为1-2秒。对于测试,可以临时设置为0秒,以观察所有SQL的详细执行情况。

第二步:临时开启慢查询日志(重启后失效)

set global slow_query_log = 'ON';
set global long_query_time = 0; -- 对新建立的连接生效
set session long_query_time = 0; -- 对当前会话立即生效

第三步:分析慢查询日志
开启后,执行一些SQL,日志文件(如/var/lib/mysql/2be4983ea86a-slow.log)中就会出现类似记录:

# Time: 2026-03-01T08:39:58.839308Z
# User@Host: root[root] @  [127.0.0.1]  Id:     9
# Query_time: 0.000484  Lock_time: 0.000004 Rows_sent: 1  Rows_examined: 1
SET timestamp=1772354398;
select * from t_user where phone="13789097853";

日志中的关键信息:

  • Query_time: SQL实际执行时间。
  • Rows_examined: MySQL为了返回结果扫描了多少行。如果这个值远大于Rows_sent(实际返回行数),通常意味着索引使用不佳,做了大量无效的扫描。

当日志文件变得庞大后,手动分析效率低下。可以使用MySQL自带的 mysqldumpslow 工具进行聚合分析:

# 查看执行时间最长的前10条SQL
mysqldumpslow -s t -t 10 /var/lib/mysql/2be4983ea86a-slow.log

命令总结

为了方便回顾,我们将这几个核心命令的作用和使用场景总结如下:

命令 作用 典型使用场景
explain 查看SQL执行计划 分析单条SQL是否走了索引,预估性能
analyze 重新统计索引信息 当MySQL因统计信息不准而选错索引时
show index 查看表的索引结构 确认索引是否建立、区分度如何、联合索引顺序
show processlist 查看当前所有连接和SQL 数据库响应变慢时,快速定位长时间运行的查询或锁等待
慢查询日志 记录执行超时的SQL 长期监控,系统性发现和优化慢SQL

掌握这五个命令,你就拥有了从实时诊断到长期监控的完整MySQL性能分析能力。实践是掌握它们的最好方式,下次遇到数据库性能问题,不妨从运行一条 EXPLAINSHOW PROCESSLIST 开始你的排查之旅吧。如果想深入学习更多数据库或系统架构相关的实战知识,欢迎来 云栈社区 与大家一起交流探讨。




上一篇:Kubernetes Pod异常定位排查指南:CrashLoopBackOff、OOMKilled常见故障分析
下一篇:OpenViking:用文件系统范式解决AI Agent的上下文管理难题
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-3 20:17 , Processed in 0.383269 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表