起因

排查“网站到底执行了哪些 SQL”是运维常见需求:某个页面突然变慢、怀疑 ORM 拼了意外的查询、想确认定时任务真的写了数据——这些都得看到服务器真实收到的每一条语句,而不是去猜代码里写了什么。

需求

  • 临时打开全量 SQL 日志,实时盯着看
  • 不重启 MySQL 实例(生产库重启窗口难约)
  • 用完即关,不留长期负担

技术实现原理

MySQL 的日志各有分工:error log 记服务器自身事件,slow log 只记超过 long_query_time 的慢查询,而 general log 记录收到的每一条语句——正是“看全部”需要的那个。

它默认是关的,原因在原理上就说不适合常开:每来一条 SQL 就写一次盘,I/O 放大直接拖吞吐;日志量与查询量成正比,高峰期能把磁盘吃满;而且语句原文(含 UPDATE/SET 里的明文密码)全落盘,本身是敏感数据。

SET GLOBAL 是运行时改全局变量、立即对新连接生效,不落配置文件、重启即失效——这既是它“临时”的由来,也是本文方案成立的根基:既不需要重启,也不会把危险配置固化下来。

设置临时开关

set global general_log='ON';

查看日志位置

show global variables like '%general%';

输出结果

+------------------+---------------------------------------------------+
| Variable_name    | Value                                             |
+------------------+---------------------------------------------------+
| general_log      | ON                                                |
| general_log_file | /usr/local/mysql/data/izj6c8l1o9y83q9flvmwoez.log |
+------------------+---------------------------------------------------+
2 rows in set (0.00 sec)

监控日志

根据上一步的 general_log_file 文件位置,执行下面命令进行监控。tail -f 会持续跟随文件末尾新增的内容,MySQL 每执行一条语句,屏幕上就实时滚出一条:

tail -f /usr/local/mysql/data/izj6c8l1o9y83q9flvmwoez.log

踩坑记录与注意事项

  • 用完必须关掉set global general_log='OFF';。常开的 general log 会随流量吃满磁盘,I/O 也在拖数据库——这本来就是它默认关闭的原因;
  • **重启后自动“恢复关闭”**是这套方案的特性不是缺陷:SET GLOBAL 不写配置文件,重启即回到 my.cnf 的默认值,不会把全量日志意外固化;
  • 只想查慢查询别开它:slow log + long_query_time 才是定位性能问题的对口工具,general log 是“看行为”用的,量级完全不同;
  • 日志里有明文敏感数据:语句原文直接落盘,文件权限要收紧,排查完可以顺手清空;
  • 不想动文件也可以落表set global log_output='TABLE'; 后查 mysql.general_log 表,用 SQL 就能过滤,但表同样会膨胀,用完一样要清理;
  • tail -f 看不到新内容时先确认实例没做日志轮转(文件被 rename/重建),必要时改用 tail -F(大写 F,文件被换掉后自动重新打开)。