MySQL调优 一:慢SQL日志

目录

    • 一、什么是慢SQL日志?
    • 二、慢查询日志的开启与配置
        1. 配置文件方式(永久生效)
        1. 动态开启(不需重启,适合临时调试)
        1. MySQL 8.0+ 新特性
    • 三、慢查询日志的内容格式
    • 四、慢查询日志分析工具
        1. mysqldumpslow(MySQL内置)
        1. pt-query-digest
        1. 其他工具
    • 五、一些使用时需注意的
      • 1.日志无限扩增问题
        1. **性能开销**

在数据库性能优化中,慢SQL日志(Slow Query Log)是最基础、最重要的诊断工具之一。它能自动记录所有执行时间超过指定阈值的SQL语句,帮助开发者与DBA快速发现潜在的性能问题。本文以MySQL为例,详细讲解慢SQL日志的原理、配置、使用、分析以及最佳实践。

一、什么是慢SQL日志?

慢SQL日志是数据库内置的一种日志机制,用于记录执行时间较长的查询语句。

MySQL中默认阈值是10秒(long_query_time = 10),但在生产环境中通常会调低到1秒甚至0.5秒。

除了执行时间超长的查询,还可以选择记录:

  • 未使用索引的查询(即使执行很快)。
  • 不进入查询缓存的查询(旧版本MySQL)。

慢查询日志的用途:

  • 发现最耗时的SQL,优先优化。
  • 分析系统整体查询性能分布。
  • 作为性能基线,监控性能变化。

二、慢查询日志的开启与配置

1. 配置文件方式(永久生效)

编辑MySQL配置文件(通常是/etc/my.cnf/etc/mysql/my.cnf)的[mysqld]部分:

ini 复制代码
[mysqld]
slow_query_log = ON                          # 开启慢查询日志
slow_query_log_file = /var/log/mysql/slow.log # 日志文件路径
long_query_time = 1                          # 阈值1秒(支持小数,如0.5)
log_queries_not_using_indexes = ON           # 可选:记录未使用索引的查询
min_examined_row_limit = 100                 # 可选:扫描行数超过该值才记录(避免小表全扫)
log_slow_admin_statements = ON               # 可选:记录慢的管理员语句(如ALTER TABLE)
log_slow_slave_statements = ON               # 可选:从库记录慢查询(复制环境)

修改后重启MySQL服务生效。

2. 动态开启(不需重启,适合临时调试)

sql 复制代码
-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;

-- 设置日志文件路径(需有权限)
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

-- 设置阈值(支持毫秒级,如0.1表示100ms)
SET GLOBAL long_query_time = 1;

-- 记录未使用索引的查询
SET GLOBAL log_queries_not_using_indexes = ON;

注意:动态设置在MySQL重启后会失效。

3. MySQL 8.0+ 新特性

  • 支持微秒级精度阈值(long_query_time可设为0.000001)。
  • 默认日志格式为文本文件,也支持写入performance_schema或系统表。

三、慢查询日志的内容格式

一条典型的慢查询日志记录包含以下部分:

ini 复制代码
# Time: 2025-12-18T10:23:45.123456Z
# User@Host: app_user[app_user] @ 192.168.1.100 []
# Thread_id: 12345  Schema: mydb  QC_hit: 0
# Query_time: 2.345678  Lock_time: 0.000123  Rows_sent: 1000  Rows_examined: 1000000
# Rows_affected: 0
SET timestamp=1734517425;
SELECT * FROM orders WHERE create_time > '2025-01-01' ORDER BY id DESC;

关键字段解释:

  • Query_time:查询执行总耗时(最重要)。
  • Lock_time:获取锁等待时间。
  • Rows_sent:返回给客户端的行数。
  • Rows_examined:扫描的行数(越大越说明可能缺少索引)。
  • SET timestamp:查询开始执行的时间戳。
  • 最后是完整的SQL语句。

四、慢查询日志分析工具

手动查看日志效率低下,推荐使用专业工具:

1. mysqldumpslow(MySQL内置)

bash 复制代码
# 按执行时间排序,取前10条
mysqldumpslow -t 10 /var/log/mysql/slow.log

# 按平均执行时间排序
mysqldumpslow -s al -t 10 /var/log/mysql/slow.log

常用参数:

  • -s:排序方式(c:次数, t:时间, al:平均时间等)
  • -t:返回前N条
  • -g:配合正则过滤特定SQL

2. pt-query-digest

功能强大,支持详细统计报告。

bash 复制代码
pt-query-digest /var/log/mysql/slow.log > slow_report.txt

输出包括:

  • 排名前N的慢查询(按总时间、平均时间、执行次数)。
  • 每条SQL的摘要(指纹,去除常量)。
  • 执行计划统计(Rows examine、Lock time等)。
  • 查询时间分布图。

示例报告片段:

ini 复制代码
# Rank Query ID           Response time  Calls  R/Call  Item
# ==== ================== ============== ====== ======= ============
# 1    0xB7E4...          1234.5678 80%   500    2.469   SELECT orders

3. 其他工具

  • EverSQL Query Optimizer:在线分析。
  • MySQL Workbench / Navicat:图形化查看。
  • ELK栈或阿里云/腾讯云的日志服务:实时监控。

五、一些使用时需注意的

1.日志无限扩增问题

慢查询日志默认写入文件(如/var/log/mysql/slow.log),高并发或阈值设置过低时,日志会快速膨胀。核心解决思路是定期轮转(rotation)和归档,结合压缩和自动清理。

解决方案.:使用logrotate实现自动轮转

Linux系统自带的logrotate工具是最成熟的方案,能每天/每周自动切割日志、压缩旧文件、保留有限份数。

步骤:

创建或编辑/etc/logrotate.d/mysql-slow文件(路径可能因系统略有差异):

复制代码
/var/log/mysql/mysql-slow.log {  # 替换为你的实际日志路径
    daily                       # 每天轮转一次(可改weekly)
    rotate 14                   # 保留14份旧日志(约2周)
    compress                    # 压缩旧日志(gzip格式,节省空间)
    delaycompress               # 延迟压缩,上一份日志先不压
    missingok                   # 如果日志不存在,不报错
    notifempty                  # 空日志不轮转
    create 660 mysql mysql      # 新日志文件权限和属主
    sharedscripts
    postrotate
        # 安全刷新日志:临时关闭慢查询,等待缓冲flush,再恢复
        /usr/bin/mysql -e "
            SET @old = @@global.long_query_time;
            SET GLOBAL slow_query_log = OFF;
            SELECT SLEEP(5);  # 等待缓冲写入
            FLUSH SLOW LOGS;
            SET GLOBAL slow_query_time = @old;
            SET GLOBAL slow_query_log = ON;
        " > /dev/null 2>&1
    endscript
}

说明:

  • postrotate脚本中临时关闭慢查询日志,然后FLUSH SLOW LOGS让MySQL重新打开新文件,避免MySQL继续写旧文件(因为MySQL持有文件句柄),继续写旧文件可能会找不到文件,无法写入。
  • 更安全的变体:使用copytruncate选项(不需flush,但可能丢失少量日志)。
  • 测试配置:sudo logrotate -d /etc/logrotate.d/mysql-slow(调试模式)。
  • 强制执行:sudo logrotate -f /etc/logrotate.d/mysql-slow

这样配置后,日志每天切割,旧日志压缩保留14天,磁盘占用可控。

2. 性能开销

慢查询日志本身开销很小(仅记录超阈值查询),但如果阈值过低或开启log_queries_not_using_indexes,会记录大量语句,增加I/O负担,所以设置合理的阈值是很有必要的。

注:如果表内数据比较少也用不到慢查询日志,本文仅针对大表导致的慢sql问题。

相关推荐
Data_Journal2 小时前
使用 PowerShell Invoke-WebRequest 配合代理的完整指南
数据库
翼龙云_cloud2 小时前
阿里云GPU卡顿、掉线如何处理?
运维·服务器·阿里云·云计算
lin张2 小时前
Docker 场景化操作:生产环境容器实践
运维·docker·容器
山川而川-R2 小时前
在香橙派5pro上的ubuntu22.04系统烧录镜像
linux·运维·服务器
学习3人组2 小时前
自动拨号和录音的App解决方案
运维
最贪吃的虎2 小时前
MySQL调优 二:explain参数详解+索引优化实战
数据库·mysql
严文文-Chris2 小时前
如何让向量数据库的“查找目录”又快又准?
数据库
武子康2 小时前
大数据-192 DataX 3.0 架构与实战:Reader/Writer 插件模型、Job/TaskGroup 调度、speed/errorLimit 配置速
大数据·分布式·后端