定时清理MySQL慢查询日志优化数据库性能
核心答案:为什么需要定时清理MySQL慢查询日志?
MySQL慢查询日志记录了执行时间超过设定阈值的SQL语句,对排查性能瓶颈很有用。
但如果长期不清理,日志文件会越积越大,占用大量磁盘空间,甚至拖慢数据库写入速度。
定时清理慢查询日志可以释放磁盘、避免日志文件过大影响数据库性能,同时保留适当的历史记录用于分析。
本文提供一套可自动执行的清理方案,包括开启日志、设置轮转、编写清理脚本和定时任务,零基础用户也能照着做。
适用场景与准备工作
这套方案适用于所有使用MySQL的环境,无论你是用宝塔面板、LNMP一键包,还是在云服务器上手动安装的MySQL。
执行前需要确认以下几点:
- 你拥有服务器root或sudo权限(或者能执行crontab命令的普通用户权限)。
- MySQL已开启慢查询日志(如果还未开启,可参考第3节一并操作)。
- 熟悉命令行(本文命令均基于Linux系统,Windows用户可参考WSL或使用计划任务)。
第一步:确认并开启MySQL慢查询日志
首先登录到服务器,用SSH工具连接。
然后检查当前是否开启了慢查询日志:
mysql -u root -p -e "SHOW VARIABLES LIKE 'slow_query_log%';"
如果 slow_query_log 的值为 OFF,则需要开启。
临时开启:
mysql -u root -p -e "SET GLOBAL slow_query_log = 1;"
永久开启需要修改MySQL配置文件(通常是 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf),在 [mysqld] 段添加:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2
long_query_time = 2 表示记录执行时间超过2秒的查询,你可以根据业务调整。
添加后重启MySQL:
systemctl restart mysql
第二步:编写日志清理脚本
创建一个清理脚本,例如 /opt/clean_mysql_slow_log.sh,内容如下:
#!/bin/bash
# 清理MySQL慢查询日志脚本
# 保留最近7天的日志,超过7天的压缩后删除源文件
LOG_DIR="/var/log/mysql"
LOG_FILE="mysql-slow.log"
RETENTION_DAYS=7
# 进入日志目录
cd "$LOG_DIR" || { echo "目录不存在"; exit 1; }
# 重命名当前日志,让MySQL继续写新文件
mv "$LOG_FILE" "${LOG_FILE}.$(date +%Y%m%d%H%M%S)"
# 通知MySQL重新打开日志文件(MySQL 8.0+ 支持)
mysqladmin flush-logs -u root -p你的数据库密码
# 删除超过保留天数的旧日志文件(包括已压缩的)
find "$LOG_DIR" -name "${LOG_FILE}.*" -mtime +$RETENTION_DAYS -exec rm -f {} \;
# 可选:将余下的历史日志压缩(节省空间),保留28天内的压缩包
# find "$LOG_DIR" -name "${LOG_FILE}.*" -mtime +7 -mtime -28 -exec gzip {} \;
注意:flush-logs会关闭并重新打开所有日志文件,包括错误日志和慢查询日志。如果MySQL版本低于5.7,建议使用mysqladmin flush-logs前确保慢查询日志文件路径正确。另外,密码直接写在脚本中有安全风险,可以用~/.my.cnf文件存放凭据,或使用--login-path方式。这里为简化教程,采用直接写密码的方式,正式环境建议使用更安全的方法。
给脚本执行权限:
chmod +x /opt/clean_mysql_slow_log.sh
第三步:设置定时任务(crontab)
运行 crontab -e 编辑当前用户的定时任务(如用root用户执行)。
添加以下一行,表示每天凌晨2点执行清理:
0 2 * * * /opt/clean_mysql_slow_log.sh >> /var/log/clean_mysql_slow.log 2>&1
解释:每天2点整执行脚本,并将标准输出和错误输出追加到日志文件中,方便排查问题。
保存后,检查crontab是否生效:
crontab -l
应该能看到刚才添加的任务。
第四步:避坑指南与注意事项
- 密码安全:脚本中明文写数据库密码存在泄露风险。建议创建
~/.my.cnf文件,权限设为600:
[client]
user=root
password=你的密码
然后在脚本中直接写 mysqladmin flush-logs 即可(不带 -u -p)。
- 日志文件大小:如果慢查询日志写入量很大(比如长查询太多),建议先优化慢查询,否则清理频率需要调高(每天执行一次可能不够)。可以根据实际文件增长情况调整保留天数或压缩策略。
- MySQL 5.6及以下版本:
flush-logs可能不会主动重新创建慢查询日志文件。需要在脚本中先清理旧日志,然后手动执行FLUSH LOGS;,或者用SET GLOBAL slow_query_log = 0; SET GLOBAL slow_query_log = 1;来重新开启。 - 日志目录权限:确保MySQL用户有权限读写日志目录。如果脚本用root执行,生成的文件属主可能为root,导致MySQL无法写入新日志。解决办法:脚本中
chown mysql:mysql /var/log/mysql/*或者目录权限设为777(不推荐)。 - 磁盘空间预警:建议同时配置磁盘空间监控,比如
df -h或使用宝塔面板的磁盘告警,避免日志突然暴涨导致磁盘满。
第五步:效果验证
手动执行一次脚本测试:
bash /opt/clean_mysql_slow_log.sh
然后检查日志目录:
ls -lh /var/log/mysql/
你应该能看到原本的 mysql-slow.log 被重命名(加上时间戳),并且生成了一个全新的空的 mysql-slow.log。
接着检查MySQL是否在正常写入新日志:生成一条慢查询(比如 SELECT SLEEP(3);),然后查看新文件里是否有记录。
tail -f /var/log/mysql/mysql-slow.log
再执行一个超过2秒的查询,观察新日志是否出现。
如果正常,说明清理和轮转都成功。
最后检查crontab是否在第二天自动执行:查看清理日志文件 /var/log/clean_mysql_slow.log,如果有输出说明定时任务正常。
常见问题解答
Q1:清理脚本执行后,MySQL写日志报错“Permission denied”怎么办?
A:脚本中重命名后,新文件权限可能不对。解决方案:在脚本中添加 chown mysql:mysql /var/log/mysql/mysql-slow.log,或确保日志目录权限为755且属主为mysql。
Q2:我不需要压缩,只想删除7天前的日志文件,可以吗?
A:可以。脚本中已有 find ... -mtime +7 -exec rm -f {} \;,注释掉 gzip 部分即可。注意:删除操作不可恢复,建议先测试。
Q3:宝塔面板如何设置定时清理慢查询日志?
A:宝塔面板自带“计划任务”功能。先通过SSH把脚本上传到服务器,然后在面板左侧“计划任务”中添加Shell脚本任务,时间选每天凌晨2点,命令写 bash /opt/clean_mysql_slow_log.sh 即可。注意脚本中的密码建议使用 ~/.my.cnf 方式。
Q4:如果MySQL版本是8.0,轮转日志有什么不同?
A:MySQL 8.0 对日志管理更完善,mysqladmin flush-logs 依然可用。也可以考虑使用 SET GLOBAL slow_query_log = 0; SET GLOBAL slow_query_log = 1; 来代替,但需注意关闭和开启之间可能有极短暂的无日志时间。
如果你在操作中遇到其他问题,欢迎在评论区留言。
建议先按本文步骤完整执行,再根据你的环境微调。
遇到异常时优先回看避坑和高频问题部分。