mysql数据库中的错误日志与慢查询日志分析

8次阅读

mysql错误日志和慢查询日志需通过log_Error、slow_query_log等变量确认是否启用;错误日志中Aborted connection、OOM、InnoDB页损坏等须立即处理;慢日志分析推荐mysqldumpslow或SQL查询mysql.slow_log表。

mysql数据库中的错误日志与慢查询日志分析

如何确认 MySQL 是否启用了错误日志和慢查询日志

MySQL 默认不一定开启这两类日志,尤其慢查询日志默认是关闭的。直接查 SHOW varIABLES LIKE '%log%' 可能返回一配置,但关键就看这几个:

  • log_error:显示错误日志路径(如 /var/log/mysql/error.log),若为空或为 NULL,说明错误日志未启用(常见于 MySQL 8.0+ 的 systemd 管理模式,日志可能走系统 journal)
  • slow_query_log:值为 OFF 表示慢查询日志关闭;ON 才启用
  • slow_query_log_file:慢日志文件路径,若未显式设置,MySQL 会按数据目录 + 主机名生成默认路径(如 /var/lib/mysql/hostname-slow.log
  • long_query_time:判定“慢”的阈值(单位秒),默认是 10.000000,生产环境建议调低到 1.00.5

注意:log_output 决定日志输出方式,FILE 写文件,table 写入 mysql.slow_log 表(需同时启用 slow_query_log),TABLE 方式方便 SQL 查询分析,但有性能开销且不记录非查询语句(如 SETDELIMITER)。

错误日志里哪些内容必须立刻关注

错误日志不是用来“定期翻阅”的,而是出问题时第一排查入口。以下几类信息出现即需人工介入:

  • Aborted connection:频繁出现说明客户端异常断连,可能是网络抖动、超时设置不合理(如 wait_timeout 太小),或应用未正确 close 连接
  • Out of memoryCannot allocate memory:不是 MySQL 内存配额超了,很可能是系统级 OOM killer 杀掉了 mysqld 进程,要查 dmesg -T | grep -i "killed process"
  • InnoDB: database page corruptionFailed to read from the .ibd file:物理页损坏,立即停止写入,用 innodb_force_recovery 尝试导出数据
  • Plugin 'validate_password' is disabled 类提示:不是错误,但说明插件加载失败,若依赖该插件做密码策略,实际策略并未生效

不要被大量 Starting crash recoveryShutdown completed 刷屏干扰——只要不是高频重启,这些属于正常启停日志。

慢查询日志分析的实用命令与过滤技巧

直接 cattail -f 看原始日志效率极低。优先用官方工具 mysqldumpslow 或结构化处理:

  • 统计最慢的 10 条语句:
    mysqldumpslow -s t -t 10 /var/lib/mysql/hostname-slow.log
  • 统计访问次数最多的 10 条:
    mysqldumpslow -s c -t 10 /var/lib/mysql/hostname-slow.log
  • 只看锁定时间超过 2 秒的:
    mysqldumpslow -s l -t 10 -g "Lock_time: [2-9]" /var/lib/mysql/hostname-slow.log
  • 如果日志是 TABLE 方式存储,可直接 SQL 分析:
    SELECT query_time, lock_time, rows_sent, rows_examined, sql_text FROM mysql.slow_log ORDER BY query_time DESC LIMIT 10;

注意:mysqldumpslow 会自动归并带不同参数的相同语句(如 WHERE id = 1WHERE id = 2 都算作 WHERE id = N),但无法识别函数或子查询变化,真实场景中仍需结合 pt-query-digest 做深度分析。

为什么开了慢日志却没记录明显慢的查询

常见原因不是配置漏了,而是语义或执行路径不符合记录条件:

  • 查询在从库执行,但 log_slow_slave_statementsOFF(MySQL 5.7+ 默认关)
  • 语句被优化器重写后实际执行很快(如命中覆盖索引,rows_examined 很小),但 query_time 仍超阈值——此时 long_query_time 是按实际执行耗时判断的,不受扫描行数影响
  • 使用了 SQL_NO_CACHESQL_CACHE 提示,但 MySQL 8.0 已移除查询缓存,这类语句会被跳过日志记录
  • 客户端连接设置了 long_query_time=0(会话级覆盖全局),但该会话后续又执行了 SET long_query_time=10,导致部分查询漏记

最隐蔽的一点:如果查询触发了隐式类型转换(比如 WHERE phone = 13800138000,而 phoneVARCHAR),优化器可能放弃索引,但 query_time 未必超限——这类问题不会出现在慢日志里,得靠 EXPLAIN 或 Performance Schema 抓。

text=ZqhQzanResources