MySQL 实战宝典(六):MySQL慢查询排查

文章介绍了如何排查MySQL中的SQL执行错误,通过错误码和错误详情定位问题,并讲解了如何配置和利用慢查询日志来优化查询性能,包括关注的参数如long_query_time,以及通过索引和分解复杂SQL进行问题排查。

一、基础排查:SQL 执行报错

当 SQL 语句无法执行时,首先要解决的是语法逻辑错误。

常用工具: Navicat, DBeaver, MySQL Workbench, CLI

1. 错误码分析

当执行出错时,MySQL 会返回 Error CodeMessage

示例错误:
1064 - You have an error in your SQL syntax; ... near '* from admin' at line 1

  • 定位方法:重点关注 near 关键字后面的内容,通常错误就发生在它的前一个单词或当前单词。
  • 常见原因
    • 关键字拼写错误(如 form 写成 from)。
    • 标点符号错误(中文逗号、缺失分号)。
    • 使用了 MySQL 保留字作为字段名且未加反引号(`)。

2. 善用搜索引擎

遇到生僻的错误码(如 ERROR 1205: Lock wait timeout exceeded),直接将 “MySQL + 错误码 + 报错信息” 放入搜索引擎。


二、进阶排查:慢查询日志 (Slow Query Log)

当系统变慢,但没有报错时,慢查询日志是捕获问题的“黑匣子”。

1. 核心参数解析

参数名说明推荐配置
slow_query_log开关,ON 开启,OFF 关闭。ON
slow_query_log_file日志文件的存储路径。/var/log/mysql/slow.log
long_query_time阈值。超过该时间的 SQL 会被记录(单位:秒)。10.5
log_queries_not_using_indexes是否记录未使用索引的 SQL。ON (前期排查时建议开启)

2. 配置实战

方式 A:命令行配置(临时生效,重启失效)

适合临时排查问题,无需重启数据库。

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL slow_query_log_file = '/var/lib/mysql/slow-query.log';
SET GLOBAL log_queries_not_using_indexes = 'ON';
SET GLOBAL long_query_time = 1; -- 记录超过1秒的SQL

验证配置:

SHOW VARIABLES LIKE '%slow_query%';

方式 B:配置文件配置(永久生效)

修改 my.cnf (Linux) 或 my.ini (Windows),添加以下内容并重启服务:

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 1
log_queries_not_using_indexes = 1

3. 日志分析技巧

直接查看日志文件

# Time: 2023-03-12T09:32:24.818300Z
# User@Host: root[root] @ localhost [::1]  Id: 11
# Query_time: 2.003975  Lock_time: 0.000116 Rows_sent: 393  Rows_examined: 100000
SET timestamp=1678613544;
SELECT * FROM orders WHERE amount < 100;
  • Query_time: 实际执行耗时(重点)。
  • Lock_time: 等待锁的时间。如果该值很高,说明存在锁竞争死锁
  • Rows_examined: 扫描行数。如果 Rows_sent 很小但 Rows_examined 很大(例如送回 10 行却扫描了 10 万行),说明索引效率极低

使用 mysqldumpslow 工具

直接看日志眼花缭乱,MySQL 自带了分析工具。

# 得到返回记录集最多的10个SQL
mysqldumpslow -s r -t 10 /var/lib/mysql/slow.log

# 得到访问次数最多的10个SQL
mysqldumpslow -s c -t 10 /var/lib/mysql/slow.log

# 得到按照时间排序的前10条里面含有左连接的查询语句
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/slow.log

三、深度分析:EXPLAIN 执行计划

找到慢 SQL 后,使用 EXPLAIN 像做“CT扫描”一样分析它的执行逻辑。

1. 性能分析概览图 (Mermaid)

在分析 type 字段时,性能从最优最差的排序如下:

性能极好

性能极差

system/const

eq_ref

ref

range

index

ALL

优化目标:至少达到 range 级别,最好是 refconst

2. 核心字段详解

(1) type - 访问类型 (最重要)

类型含义场景示例
system/const只有一行匹配,极快主键或唯一索引查找 WHERE id = 1
eq_ref唯一索引扫描多表连接时,使用主键或唯一索引关联
ref非唯一索引扫描WHERE user_name = 'Tom' (普通索引)
range索引范围扫描WHERE id > 10BETWEEN
index全索引扫描SELECT id FROM table (扫描整个索引树,不回表)
ALL全表扫描SELECT * FROM table (无索引,数据量大时必死)

(2) key_len - 索引使用的长度

  • 作用:判断联合索引是否被完全使用。
  • 示例:联合索引 (a, b, c),如果 key_len 只显示了列 a 的长度,说明 bc 没用到,索引失效中断了。

(3) Extra - 额外信息 (调优金钥匙)

评价含义与建议
Using index🟢 完美覆盖索引。查询列全在索引中,无需回表,性能最高。
Using where🟡 一般存储引擎返回数据后,Server 层还在过滤。
Using index condition🟡 不错索引下推。MySQL 5.6+ 优化,减少回表次数。
Using temporary🔴 警告产生了临时表(常见于 GROUP BYDISTINCT)。需优化索引或 SQL 逻辑。
Using filesort🔴 严重文件排序。无法利用索引顺序,需在内存/磁盘排序。需优化 ORDER BY 字段索引。

四、实战案例分析

假设表结构:

  • users: id (PK), name (index), age, city
  • orders: id (PK), user_id (index), create_time

案例 1:高效的关联查询

EXPLAIN SELECT u.name, o.amount 
FROM users u 
JOIN orders o ON u.id = o.user_id 
WHERE o.create_time > '2023-01-01';

分析结果:

  • orderstyperange (利用 create_time 索引)。
  • userstypeeq_ref (利用主键 id 关联)。
  • 结论:性能良好。

案例 2:全表扫描灾难

EXPLAIN SELECT * FROM users WHERE age > 30;

分析结果:

  • type: ALL (全表扫描)。
  • key: NULL (无索引可用)。
  • 优化:给 age 字段添加索引。

案例 3:文件排序 (Using filesort)

EXPLAIN SELECT * FROM users ORDER BY city;

分析结果:

  • Extra: Using filesort。因为 city 字段没有索引,MySQL 必须将所有数据加载排序。
  • 优化:给 city 建立索引,或者避免对无索引字段进行全表排序。

五、总结:MySQL 问题排查全流程

Lock_time 高

Rows_examined 大

是 ALL/index

是 range/ref

filesort/temporary

Using index

发现数据库变慢/报错

有报错信息?

排查语法/表名/字段

重试 SQL

查看慢查询日志

定位到具体慢 SQL

分析耗时原因

排查死锁/事务堆积

执行 EXPLAIN

检查 type 字段

添加/优化索引

检查 Extra 字段

优化 SQL 写法/联合索引

优化完成


参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TracyCoder123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值