MySQL 日志类型与配置
一、MySQL 日志类型概述
MySQL Server 在运行过程中会生成多种日志,用于记录服务器状态、客户端请求、语句执行和故障排查等信息。
| 日志类型 | 作用 | 默认状态 |
|---|---|---|
error log |
记录服务器启动、运行和停止过程中的关键事件 | 始终启用 |
general query log |
记录所有客户端连接和接收到的 SQL 语句 | 默认关闭 |
binary log |
记录数据变更(用于复制和增量恢复) | 默认启用 |
slow query log |
记录执行时间超过阈值的查询 | 默认关闭 |
二、错误日志
错误日志记录服务器启动、运行、停止过程中的关键事件,以及警告和错误信息,是排查 MySQL 故障的主要信息来源。
2.1 默认路径与配置
在 Unix/Linux 系统中,mysqld 通过 --log-error 选项决定错误日志的默认目标:
| 启动方式 | 默认行为 |
|---|---|
未指定 --log-error |
输出到控制台(stderr) |
--log-error(无文件名) |
输出到 host_name.err,位于数据目录 |
--log-error=file_name |
输出到指定文件,自动添加 .err 后缀 |
验证:
1 | |
1 | |
本机错误日志路径为 /var/log/mysql/mysqld.log。
修改日志路径示例(在配置文件中,路径为 /etc/my.cnf.d/mysql-server.cnf):
1 | |
RPM 或 APT 包安装时通常配置为
/var/log/mysqld.log。移除路径名后,改为数据目录下的host_name.err。
2.2 日志格式
log_sink_internal 产生的传统错误日志格式为:
1 | |
每条消息包含:时间戳、线程 ID、优先级标签、错误码、子系统、消息内容。
label 为优先级的字符串形式,对应关系如下:
| 优先级 | prio 值 |
label 字符串 |
|---|---|---|
SYSTEM |
0 | System |
ERROR |
1 | Error |
WARNING |
2 | Warning |
INFORMATION |
3 | Note 或 Information |
SYSTEM 优先级为启动/关闭等系统消息,无法被过滤。
subsystem 标识产生该事件的 MySQL 子系统:
subsystem 值 |
说明 |
|---|---|
InnoDB |
InnoDB 存储引擎 |
Repl |
复制子系统 |
Server |
服务器通用部分 |
时间戳格式由 log_timestamps 控制:
1 | |
1 | |
可选值为 UTC(默认)和 SYSTEM(本地时区)。时间戳格式为 ISO 8601/RFC 3339:
1 | |
2.3 日志过滤
错误日志组件体系由过滤器(filter)和写入器(sink)组成。过滤器处理日志事件,写入器负责输出到具体目的地。
2.3.1 优先级过滤(log_filter_internal)
log_filter_internal 是内置的优先级过滤器,受 log_error_verbosity 控制:
1 | |
1 | |
log_error_verbosity 值 |
记录的优先级 |
|---|---|
| 1 | ERROR |
| 2 | ERROR, WARNING(默认) |
| 3 | ERROR, WARNING, INFORMATION |
优先级含义:
| 优先级 | 数字值 | 说明 |
|---|---|---|
| SYSTEM | 0 | 启动/关闭等系统消息,无法过滤 |
| ERROR | 1 | 错误 |
| WARNING | 2 | 警告 |
| INFORMATION | 3 | 信息 |
另外,log_error_suppression_list 可按错误码压制特定消息(仅对 WARNING 和 INFORMATION 生效):
1 | |
错误码支持符号名(如 ER_PARSER_TRACE)、带 MY- 前缀(如 MY-010001)或纯数字(如 10002)。符号名优于数字,可读性更好。
优先级过滤规则(与 log_error_verbosity 等效):
| 规则 | 等效 log_error_verbosity |
|---|---|
IF prio > ERROR THEN drop. |
1(仅 ERROR) |
IF prio > WARNING THEN drop. |
2(ERROR + WARNING) |
IF prio > INFORMATION THEN drop. |
3(全部) |
2.3.2 规则过滤(log_filter_dragnet)
log_filter_dragnet 支持用户自定义规则过滤。先加载组件,再配置:
1 | |
通过 dragnet.log_error_filter_rules 设置规则,规则以 IF condition THEN action. 格式编写:
1 | |
支持的 action 包括:
| action | 说明 |
|---|---|
drop |
丢弃该日志事件 |
throttle count 或 count/window_size |
限流,限制单位时间内的记录次数 |
set field = value |
设置字段值 |
unset field |
移除字段 |
限流示例——每 60 秒最多记录 1 条 INFORMATION 级别事件:
1 | |
log_filter_dragnet启用后,log_error_suppression_list不再生效。
2.4 JSON 格式输出
log_sink_json 将错误日志输出为 JSON 格式。先加载组件:
1 | |
JSON 格式每条消息包含键值对,例如:
1 | |
其中 ts 为毫秒级 Unix 时间戳,可用 FROM_UNIXTIME() 转换:
1 | |
1 | |
log_sink_json 允许多次出现,可同时写入未过滤和已过滤的事件:
1 | |
多个实例的输出文件以 .00.json、.01.json 递增编号。
2.5 输出到系统日志
log_sink_syseventlog 将错误日志写入系统日志(Unix 的 syslog 或 Windows 的 Event Log):
1 | |
相关系统变量:
| 变量 | 说明 | 默认值 |
|---|---|---|
syseventlog.facility |
syslog 的 facility 类型 |
daemon |
syseventlog.include_pid |
是否包含进程 ID | 取决于平台 |
syseventlog.tag |
在 mysqld 标识后追加的标签 |
未设置 |
Windows 上日志来源标记为 MySQL(或 MySQL-tag),Unix 上写入 syslog。
2.6 日志刷新与重命名
手动刷新错误日志时,服务器关闭并重新打开日志文件。操作前应先重命名旧文件:
1 | |
如果服务器无法写入日志文件(例如
/var/log目录属主为root),刷新操作无法创建新文件,此时需手动创建文件并赋予正确权限。
三、通用查询日志
通用查询日志记录所有客户端的连接断开信息和接收到的每条 SQL 语句。当怀疑客户端发送了错误语句时,可通过该日志精确还原客户端请求。
1 | |
1 | |
默认关闭。启用并指定输出目标:
1 | |
默认输出目标为
FILE。如果设为NONE,即使general_log = 1也不会记录。
永久配置: 在配置文件中设置(/etc/my.cnf.d/mysql-server.cnf):
1 | |
临时配置: 运行时 SET GLOBAL(重启后失效):
1 | |
3.1 输出目标为 TABLE 时的存储
log_output = 'TABLE' 时,日志数据存储在 mysql.general_log 表中:
1 | |
1 | |
表结构说明:
| 字段 | 说明 |
|---|---|
event_time |
事件时间戳,精度到微秒 |
user_host |
客户端用户和主机信息 |
thread_id |
连接线程 ID |
server_id |
服务器 ID |
command_type |
命令类型 |
argument |
执行的语句内容(二进制格式) |
command_type 字段支持的类型:
command_type 值 |
说明 |
|---|---|
Connect |
客户端连接或断开连接 |
Query |
执行的 SQL 查询语句 |
Quit |
客户端退出连接 |
Prepare |
预处理语句(PREPARE) |
Execute |
执行预处理语句(EXECUTE) |
Init DB |
切换数据库(USE db_name) |
查看日志内容:
1 | |
argument字段类型为mediumblob,存储的是二进制内容。使用CONVERT(argument USING utf8mb4)或CAST(argument AS CHAR)将其转换为可读字符串。
该表默认使用
CSV存储引擎,也可转换为MyISAM引擎。INSERT、DELETE、UPDATE操作只能在服务器内部进行,用户无法直接修改日志表。
3.2 会话级禁用
会话级禁用通用查询日志(需 general_log = 1 前提下):
1 | |
密码在日志中会被自动重写,不会明文出现。如果需要诊断目的查看原始语句,可使用 --log-raw 选项启动服务器(生产环境慎用)。
日志记录顺序为服务器接收顺序,与执行顺序可能不一致。不同于二进制日志(先执行后记录),通用查询日志可能包含未实际执行的语句。
四、二进制日志
二进制日志记录数据库的数据变更事件,用于复制和增量恢复。默认启用。
4.1 默认配置
1 | |
1 | |
二进制日志文件位于 /var/lib/mysql/ 目录下:
1 | |
1 | |
日志文件说明:
| 文件 | 说明 |
|---|---|
binlog.000001 等 |
二进制日志文件,编号递增 |
binlog.index |
二进制日志索引文件,记录所有日志文件名 |
4.2 三种日志格式
binlog_format 系统变量控制二进制日志的格式:
| 格式 | 说明 |
|---|---|
STATEMENT |
记录实际执行的 SQL 语句(基于语句的复制) |
ROW |
记录每行数据的变更(基于行的复制,默认) |
MIXED |
默认使用 STATEMENT,在特定条件下自动切换为 ROW |
运行时切换:
1 | |
MIXED 模式自动切换为 ROW 的条件包括:
- 语句中包含
UUID() - 包含
AUTO_INCREMENT列的表触发存储过程/函数 - 视图创建时需要
ROW格式 - 调用了可加载函数
- 使用了
FOUND_ROWS()、ROW_COUNT() - 使用了
USER()、CURRENT_USER() - 涉及
mysql数据库中的日志表 - 使用了
LOAD_FILE() - 引用了某些系统变量
1 | |
1 | |
ROW 模式下,所有修改数据的语句都以行变化形式记录。但部分语句(如 CREATE TABLE、ALTER TABLE 等 DDL)仍以语句形式记录。
使用 mysqlbinlog 查看 ROW 格式日志时,必须加 -v 选项才能将行事件还原为可读 SQL,否则显示为二进制标记:
1 | |
使用
STATEMENT格式时,某些不确定的语句可能导致主从数据不一致。ROW格式精度更高,但日志体积通常更大。
4.3 查看二进制日志内容
方式一:SQL 语句
1 | |
1 | |
主要事件类型说明:
| Event_type | 说明 |
|---|---|
Format_desc |
日志格式描述 |
Previous_gtids |
前一个日志的 GTID 集合 |
Gtid |
GTID 事务标识 |
Query |
DDL/DML 语句 |
Xid |
事务提交标识 |
Table_map |
表结构映射 |
Write_rows / Update_rows / Delete_rows |
行数据变更(ROW 格式) |
查看日志事件:
1 | |
过滤特定数据库的变更:
1 | |
SHOW BINLOG EVENTS不支持WHERE子句,也无法直接按数据库过滤。查看特定数据库的变更需要结合外部工具。
方式二:mysqlbinlog 命令行工具
1 | |
常用选项:
| 选项 | 说明 |
|---|---|
--start-position=# |
从指定位置开始读取 |
--stop-position=# |
读到指定位置停止 |
--start-datetime=datetime |
从指定时间开始读取 |
--stop-datetime=datetime |
读到指定时间停止 |
--database=db_name |
只显示指定数据库的事件 |
-v, --verbose |
将行事件重构为可读 SQL(-vv 包含更多列信息) |
--include-gtids=gtid_set |
只输出指定 GTID 的事务 |
--exclude-gtids=gtid_set |
排除指定 GTID 的事务 |
--stop-never |
持续监听新事件(用于实时跟踪) |
--raw |
输出原始二进制格式(需配合 -R 远程读取) |
常用示例:
1 | |
mysqlbinlog需要读取权限,可能需要sudo或调整文件权限。-v选项可显示更详细的可读格式,--base64-output=DECODE_ROWS解码行事件。
4.4 二进制日志事务压缩
MySQL 8.0.20+ 支持二进制日志事务压缩,使用 zstd 算法压缩事务载荷:
1 | |
压缩级别可通过 binlog_transaction_compression_level_zstd 设置(1 到 22,越高压缩率越大):
1 | |
以下事件不压缩,始终以原始形式写入:
- GTID 相关事件
- 控制事件(视图变更、心跳等)
- 事件和事务(包含 incident 事件的事务)
- 非事务引擎的事件和事务
- 语句格式的日志记录
加密和压缩可同时启用。启用后,副本接收到压缩载荷,直接写入中继日志,解压后应用事件,再压缩写入自己的二进制日志。
可通过 performance_schema.binary_log_transaction_compression_stats 表监控压缩效果。
五、慢查询日志
慢查询日志记录执行时间超过 long_query_time 秒且检查行数至少达到 min_examined_row_limit 的查询。默认关闭。
1 | |
1 | |
long_query_time 默认 10 秒,最小值 0,可精确到微秒:
1 | |
慢查询日志的输出目标由 log_output 系统变量控制,与通用查询日志共享同一配置:
| 值 | 说明 |
|---|---|
FILE |
写入日志文件(默认) |
TABLE |
写入 mysql.slow_log 表 |
FILE,TABLE |
同时写入文件和表 |
NONE |
不记录,即使 slow_query_log = 1 也不记录 |
1 | |
5.1 输出为 FILE
log_output = 'FILE' 时,慢查询日志写入文件。
启用慢查询日志:
1 | |
启用后,可在 FILE 输出中记录更丰富的调试信息。log_slow_extra 是 MySQL 8.0.14 引入的系统变量,默认关闭。启用后,慢查询日志除了包含基本字段外,还输出 Handler 读操作统计、排序统计、临时表统计等信息:
1 | |
或在配置文件中设置:
1 | |
日志文件路径由 slow_query_log_file 控制,默认为数据目录下的 host_name-slow.log:
1 | |
文件每条记录格式:
1 | |
启用 log_slow_extra 后,FILE 输出包含更多字段:
| 字段 | 说明 |
|---|---|
Query_time |
执行时长(秒) |
Lock_time |
锁等待时长 |
Rows_sent |
发送给客户端的行数 |
Rows_examined |
服务器层检查的行数(不含存储引擎内部处理) |
Thread_id |
语句线程标识 |
Bytes_received |
从客户端接收的字节数 |
Bytes_sent |
发送给客户端的字节数 |
Read_first/Key/Next/Prev 等 |
各类 Handler 读操作统计 |
Sort_merge_passes |
排序合并遍历次数 |
Created_tmp_disk_tables |
磁盘创建临时表数 |
Created_tmp_tables |
内存创建临时表数 |
Start / End |
执行开始和结束时间戳 |
mysqldumpslow 工具可汇总慢查询日志:
1 | |
5.2 输出为 TABLE
log_output = 'TABLE' 时,慢查询日志写入 mysql.slow_log 表:
1 | |
表结构:
1 | |
slow_log 表结构与 general_log 类似,包含 start_time、user_host、query_time、rows_examined、rows_sent、db、sql_text 等字段。sql_text 字段类型为 blob,查看时需转换:
1 | |
5.3 记录条件与参数
服务器判断是否记录某查询的顺序:
- 管理语句必须
log_slow_admin_statements = 1才能记录 - 执行时间达到
long_query_time或log_queries_not_using_indexes = 1且未使用索引 - 检查行数达到
min_examined_row_limit - 未被
log_throttle_queries_not_using_indexes压制
常用参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
slow_query_log |
0 | 是否启用 |
long_query_time |
10.0 秒 | 触发阈值,最小 0,可精确到微秒 |
min_examined_row_limit |
0 | 检查行数下限 |
log_slow_admin_statements |
0 | 是否记录管理语句 |
log_queries_not_using_indexes |
0 | 是否记录未使用索引的查询 |
log_throttle_queries_not_using_indexes |
0 | 每分钟压制未使用索引查询数量上限 |
log_slow_extra |
0 | 是否输出额外字段(FILE 模式) |
启用未使用索引的查询记录并压制(每分钟最多 10 条):
1 | |
六、日志维护
6.1 日志刷新
执行 FLUSH LOGS 或 mysqladmin flush-logs 后,服务器重新打开各日志文件:
| 日志类型 | 刷新行为 |
|---|---|
| 二进制日志 | 关闭当前文件,创建新文件(递增编号) |
| 通用查询日志 / 慢查询日志 | 关闭并重新打开文件(不创建新文件) |
| 错误日志 | 关闭并重新打开文件(不创建新文件) |
刷新前应先重命名旧文件,否则日志内容被覆盖。
Unix 信号刷新日志(无需连接服务器):
1 | |
SIGHUP:刷新所有日志,但有其他副作用SIGUSR1:仅刷新错误日志、通用查询日志、慢查询日志,更轻量
6.2 二进制日志清理
自动过期: 二进制日志默认 30 天后自动删除,通过 binlog_expire_logs_seconds 控制:
1 | |
手动清理: 使用 PURGE BINARY LOGS 删除指定日期或文件之前的日志:
1 | |
全部删除: RESET BINARY LOGS AND GTIDS 慎用,会删除所有二进制日志。
在主从复制环境中,删除二进制日志前应确保所有从库已完成同步。
6.3 日志文件权限问题
日志文件所在目录若无写权限(如 /var/log 属主为 root),日志刷新无法创建新文件。解决方案:
1 | |