针对 MySQL 的慢查询和主从延迟问题,进行根因分析可以遵循一套系统化的排查流程。这两个问题虽然表现不同,但根源常常交织在一起。
🐢 慢查询根因分析
慢查询通常是导致数据库整体性能下降和主从延迟的直接原因。排查的核心在于定位 和分析。
1. 定位慢查询
首先,需要开启慢查询日志来捕获执行时间过长的 SQL 语句。
开启慢查询日志:可以通过修改配置文件或动态设置来开启。
sql
-- 动态开启慢查询日志(无需重启)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- 设置阈值为1秒,可根据业务调整
SET GLOBAL log_queries_not_using_indexes = 'ON'; -- 记录未使用索引的查询,非常有用
- 分析慢查询日志 :原始的慢查询日志可能非常庞大,需要使用工具进行分析。
-
pt-query-digest(推荐) :Percona Toolkit 中的工具,功能强大,能生成详细的分析报告,按总耗时、执行频率等对 SQL 进行排序,快速定位最耗资源的 SQL。bashpt-query-digest /path/to/mysql-slow.log > slow_report.txt -
mysqldumpslow:MySQL 自带的工具,可以对慢查询日志进行汇总和排序。bashmysqldumpslow -s t -t 10 /path/to/mysql-slow.log # 按平均查询时间排序,取前10条
-
2. 分析根因
定位到具体的慢 SQL 后,下一步是分析它为什么慢。
-
使用
EXPLAIN分析执行计划 :这是最关键的一步。EXPLAIN可以展示 MySQL 如何执行一条查询,帮助你判断是否存在全表扫描、索引使用不当等问题。sql1EXPLAIN SELECT * FROM orders WHERE user_id = 1001 AND status = 'paid';- 关注重点 :
type:连接类型。ALL表示全表扫描,性能最差;index表示全索引扫描;range表示索引范围扫描,是较好的结果。key:实际使用的索引。如果为NULL,则说明没有使用索引。rows:MySQL 估计需要扫描的行数。数值越大,性能越差。Extra:额外信息。Using filesort(需要额外排序)和Using temporary(使用了临时表)通常意味着性能瓶颈。
- 关注重点 :
-
检查锁竞争:慢查询也可能是因为等待锁。可以通过以下命令查看当前的锁等待情况。
sqlSELECT * FROM information_schema.innodb_lock_waits;
🔗 主从延迟根因分析
主从延迟的本质是从库重放事务的速度跟不上主库生成事务的速度。分析的关键在于判断延迟发生在哪个环节。
1. 确认延迟状态
使用 SHOW SLAVE STATUS\G 命令查看从库的复制状态,重点关注以下指标:
Seconds_Behind_Master:最直观的延迟秒数,但不够精确。Master_Log_File/Read_Master_Log_Pos:从库的 I/O 线程已经读取到的主库 Binlog 文件和位置。Relay_Master_Log_File/Exec_Master_Log_Pos:从库的 SQL 线程已经执行完的主库 Binlog 文件和位置。
通过对比 Read_Master_Log_Pos 和 Exec_Master_Log_Pos,可以判断延迟的瓶颈:
- 如果两者差距不大,但都落后于主库,问题可能出在网络传输或主库写入压力过大。
- 如果
Read_Master_Log_Pos远大于Exec_Master_Log_Pos,说明 I/O 线程正常,但 SQL 线程执行过慢,这是最常见的情况。
2. 排查延迟根因
当确定是 SQL 线程执行过慢时,可以从以下几个方面深入排查:
| 排查方向 | 具体操作与说明 |
|---|---|
| 从库负载与资源 | 1. 检查系统负载 :使用 top、iostat -x 1 等命令查看从库的 CPU、I/O 使用率。如果 %util 接近 100%,说明磁盘 I/O 是瓶颈。 2. 检查额外负载:确认从库是否承担了繁重的报表查询或备份任务,挤占了复制线程的资源。 |
| SQL 线程执行情况 | 1. 检查中继日志堆积 :SHOW GLOBAL STATUS LIKE 'Relay_log_space'; 如果该值持续增长,说明中继日志在堆积,SQL 线程处理不过来。 2. 查看当前执行的 SQL :SHOW PROCESSLIST; 查看 Command 列为 Slave_SQL 的线程正在执行什么 SQL,这通常就是导致延迟的慢查询。 |
| 主库写入压力 | 1. 大事务 :主库上的批量更新/删除、大表 DDL 操作会生成巨大的 Binlog 事件,从库需要很长时间才能重放。 2. 高并发写入:主库写入 QPS 过高,Binlog 生成速度远超从库处理能力。 |
| 复制配置 | 1. 检查并行复制 :执行 SHOW VARIABLES LIKE 'slave_parallel_workers';。如果值为 0 或 1,说明是单线程复制,在 MySQL 5.7+ 版本中应开启并行复制(如设置为 LOGICAL_CLOCK 模式)以提升性能。 2. 检查其他参数 :如 innodb_buffer_pool_size 是否过小,导致缓存命中率低。 |