定时自动清理MySQL慢查询日志释放磁盘存储空间
MySQL慢查询日志记录了执行时间较长的SQL语句,对数据库调优很有帮助。
但如果你开启了慢查询日志,却没有定期清理,日志文件会像滚雪球一样越积越大——特别是流量大的站点,几周就能吃掉几GB甚至几十GB的磁盘空间,最终导致数据库写入失败。
本文会从零开始,教你用cron加上一个简单的清理脚本,实现定时自动清理MySQL慢查询日志,安全释放磁盘空间。
整个过程不需要修改MySQL配置文件,零基础也能照做。
第一步:确认慢查询日志的开启状态和文件路径
在开始之前,先登录你的服务器(通过SSH或者宝塔面板的终端),连接到MySQL命令行:
mysql -u root -p
进入MySQL后,执行以下命令查看慢查询日志的配置:
SHOW VARIABLES LIKE 'slow_query_log%';
重点关注两行:
slow_query_log:值为ON表示已开启;如果为OFF,说明没有慢查询日志,那你就不需要清理。slow_query_log_file:这是日志文件的完整路径,比如/var/lib/mysql/server-slow.log。
同时你还可以查看日志的大小:
ls -lh /var/lib/mysql/server-slow.log
如果文件已经很大(比如几百MB甚至GB),那下面的清理就很有必要了。
记下文件路径,后面写脚本时要用到。
第二步:编写安全清理脚本(推荐使用truncate而非直接删除)
直接 rm 删除日志文件并不可靠,因为MySQL进程可能仍然持有已删除文件的句柄,导致磁盘空间不会立刻释放,甚至可能报错。
更安全的做法是:先清空文件内容而不删除文件本身。
我们可以用 truncate 命令或 : > file 的方式完成。
创建一个脚本文件,比如 /root/clean_slowlog.sh,内容如下:
#!/bin/bash
# 慢查询日志文件路径(替换成你查到的实际路径)
SLOW_LOG="/var/lib/mysql/server-slow.log"
# 设置日志大小阈值,单位MB(这里设置为50MB,超过则清理)
THRESHOLD_MB=50
if [ -f "$SLOW_LOG" ]; then
# 获取文件大小(字节)
FILESIZE=$(stat -c%s "$SLOW_LOG")
# 转换为MB
FILESIZE_MB=$(( FILESIZE / 1024 / 1024 ))
if [ $FILESIZE_MB -gt $THRESHOLD_MB ]; then
# 清空文件内容
: > "$SLOW_LOG"
# 可选:记录一条清理日志
echo "$(date) - 慢查询日志已超过${THRESHOLD_MB}MB,已清空释放空间。" >> /var/log/clean_slowlog.log
fi
fi
说明:
-stat -c%s用于获取文件大小(字节),然后换算成MB。
-: > file是清空文件的常见写法,等效于truncate -s 0 file。
- 脚本中加入了阈值判断,只有当文件超过50MB时才清理,避免频繁清空。你可以根据实际磁盘情况调整这个值。
赋予执行权限:
chmod +x /root/clean_slowlog.sh
第三步:配置cron定时任务实现自动清理
cron是Linux自带的定时任务工具,适合固定周期执行清理脚本。
我们设置每天凌晨3点执行一次,避开业务高峰期。
编辑当前用户的crontab:
crontab -e
(如果是第一次使用,可能会提示选择编辑器,选nano或vim即可。
)
在文件末尾添加一行:
0 3 * * * /root/clean_slowlog.sh
保存并退出。
cron就会加载新任务,每天凌晨3点执行一次清理检查。
如果你想在添加后就测试一下脚本是否可运行,可以手动执行:
bash /root/clean_slowlog.sh
然后检查日志文件是否被清空:
cat /var/lib/mysql/server-slow.log
正常情况下文件内容应该为空(或已大幅减小)。
第四步:避坑指南&高频问题解答
问题1:执行脚本后MySQL报错“Can't find file”
可能原因:日志文件路径不对或MySQL使用的不是同一个文件句柄。先确认 SHOW VARIABLES LIKE 'slow_query_log_file' 返回的路径是否与脚本中的一致。如果服务器使用systemd管理MySQL,可以考虑在清空后执行 mysqladmin flush-logs 来重新加载日志,但注意flush-logs也会触发二进制日志轮转,如果你的二进制日志不重要,可以忽略。更简单的做法:清空操作一般不会影响MySQL写入,因为mysql继续往同一个已打开的文件描述符写数据,清空后新内容可以正常写入。如果遇到问题,可以重启mysql服务,但生产环境不建议为了清理日志重启。
问题2:cron定时任务没有执行
检查cron服务是否运行:systemctl status crond 或 service cron status。如果cron运行正常,可以查看cron日志(一般在/var/log/cron)确认任务是否触发。另外注意脚本中的环境变量问题:cron执行时的PATH可能不完整,建议在脚本中加上 #!/bin/bash 并且显式使用绝对路径(我们已经用了绝对路径)。
问题3:每次清空后,新的慢查询日志何时才会继续写入?
清空操作后,MySQL会继续往同一个文件追加新的慢查询记录,不会中断,你不需要做任何额外操作。但如果你删除了原文件然后重新创建,可能会出现MySQL继续写入已删除文件的旧句柄。因此我们采用“清空”而非“删除”,这是关键区别。
问题4:我能手动执行一下看效果吗?
可以。手动执行脚本,然后用 ls -lh /var/lib/mysql/server-slow.log 查看文件大小;如果之前文件超过50MB,现在应该会变成接近0字节。同时可以查看 /var/log/clean_slowlog.log 确认有清理记录。
第五步:验证自动清理是否顺利运行
验证一:查看cron日志
tail -f /var/log/cron
找到凌晨3点附近的行,确认有执行记录。
验证二:查看清理日志
cat /var/log/clean_slowlog.log
如果看到多条记录,说明脚本在预期时间运行并清理了日志。
验证三:观察磁盘空间
df -h
对比清理前后的磁盘使用率,通常你会看到空间有明显释放。
验证四:确认慢查询日志依然存在且文件大小可控
ls -lh /var/lib/mysql/server-slow.log
文件应该存在,且大小不超过设定的阈值。
如果你发现清理后空间没有释放,请回头检查 避坑问题1:是否因为误用了 rm 而不是 truncate。
如果没问题,那可能日志文件太大,你的阈值设得太高,先手动减小阈值或直接运行一次清空命令看看效果。
总结
通过以上几步,你就实现了MySQL慢查询日志的定时自动清理。
核心是:用cron + 一个安全清空文件的脚本,每天检查日志大小并清空超过阈值的文件。
脚本采用 : > file 清空而不用 rm,避免了MySQL句柄问题;
加上阈值判断,避免频繁清理。
这套方案完全不需要改MySQL配置或重启服务,适合零基础用户放心使用。
如果你使用的是宝塔面板,也可以通过面板的计划任务功能直接添加相同的脚本,原理一样。
如果你在实践中遇到其它异常,欢迎在评论区提出,我会继续补充常见问题。
如果你对MySQL日志管理还有其他需求,比如自动删除二进制日志、错误日志轮转,可以继续查看站内相关教程,这里不展开。
希望本文能帮你把磁盘空间问题彻底解决。