Skip to content

第31章 MySQL 日志系统 ​

本章目标 ​

  1. 全面掌握 MySQL 的五大日志系统及其用途
  2. 理解每种日志的配置、查看、分析和管理方法
  3. 掌握慢查询日志的捕获和分析,能够使用 mysqldumpslow 和 pt-query-digest
  4. 深入理解 Redo Log、Undo Log 和 Binary Log 三者的区别与协作关系
  5. 掌握 InnoDB 的 WAL(Write-Ahead Logging)机制和崩溃恢复原理
  6. 理解各日志在生产环境中的最佳配置实践

前置知识 ​

  • 了解 MySQL 的基本架构(连接层、服务层、存储引擎层)
  • 理解事务的 ACID 特性
  • 了解 InnoDB 存储引擎的基本概念
  • 具有 MySQL 配置文件(my.cnf / my.ini)的基本操作经验

31.1 错误日志 (Error Log) ​

31.1.1 是什么 ​

错误日志记录了 MySQL 服务器的启动/关闭事件、运行中遇到的错误和警告、以及重要的状态变化。它是排查 MySQL 问题的第一个信息来源。

31.1.2 配置与查看 ​

sql
-- 查看错误日志位置
SHOW VARIABLES LIKE 'log_error';

-- 典型输出:
-- +---------------+-----------------------------------+
-- | Variable_name | Value                             |
-- +---------------+-----------------------------------+
-- | log_error     | /var/log/mysql/error.log          |
-- +---------------+-----------------------------------+

-- 查看日志详细级别
SHOW VARIABLES LIKE 'log_error_verbosity';

-- 详细级别说明:
-- 1 = 仅错误(ERROR)
-- 2 = 错误 + 警告(ERROR + WARNING)
-- 3 = 错误 + 警告 + 信息(ERROR + WARNING + NOTE)—— MySQL 8.0 默认值
ini
# my.cnf / my.ini 配置
[mysqld]
log_error = /var/log/mysql/error.log       # 错误日志文件路径
log_error_verbosity = 3                    # 日志详细级别(1/2/3)

31.1.3 错误日志包含的内容 ​

text
### 启动信息
2024-01-15T08:00:00.123456Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.35) starting as process 1234

### InnoDB 初始化
2024-01-15T08:00:01.234567Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-01-15T08:00:03.345678Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.

### 端口监听
2024-01-15T08:00:04.456789Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.35'. socket: '/var/run/mysqld/mysqld.sock'. port: 3306.

### 连接异常
2024-01-15T09:30:00.567890Z 100 [Warning] [MY-010068] [Server] Aborted connection 100 to db: 'mydb' user: 'app_user' host: '192.168.1.100' (Got timeout reading communication packets)

### 复制错误
2024-01-15T10:00:00.678901Z 50 [ERROR] [MY-010584] [Repl] Slave SQL for channel '': Error 'Duplicate entry '123' for key 'PRIMARY'' on query. Default database: 'mydb'. Query: 'INSERT INTO users VALUES (123, ...)', Error_code: MY-001062

### 崩溃恢复
2024-01-15T10:30:00.789012Z 0 [System] [MY-013722] [InnoDB] Database was not shutdown normally!
2024-01-15T10:30:00.890123Z 0 [System] [MY-013723] [InnoDB] Starting crash recovery.
2024-01-15T10:30:05.901234Z 0 [System] [MY-013724] [InnoDB] End of crash recovery.

31.1.4 错误日志的日常使用 ​

bash
# 监控错误日志(实时跟踪)
tail -f /var/log/mysql/error.log

# 查找最近的错误
grep -i "error" /var/log/mysql/error.log | tail -20

# 查找连接异常
grep "Aborted connection" /var/log/mysql/error.log | wc -l

# 按日期筛选日志
grep "2024-01-15" /var/log/mysql/error.log

# 搜索特定错误码
grep "MY-001062" /var/log/mysql/error.log  # 1062 = 重复键错误

# 日志轮转(推荐使用 logrotate)
# /etc/logrotate.d/mysql
# /var/log/mysql/error.log {
#     daily
#     rotate 30
#     missingok
#     compress
#     postrotate
#         mysqladmin flush-logs
#     endscript
# }

31.2 通用查询日志 (General Query Log) ​

31.2.1 是什么 ​

通用查询日志记录了每一个客户端连接、断开连接和每一条执行的 SQL 语句。它是最详细的日志,但由于记录量巨大,通常仅在调试和审计时临时启用。

31.2.2 配置 ​

sql
-- 查看通用日志状态
SHOW VARIABLES LIKE 'general_log%';

-- +------------------+----------------------------------+
-- | Variable_name    | Value                            |
-- +------------------+----------------------------------+
-- | general_log      | OFF                              |
-- | general_log_file | /var/lib/mysql/hostname.log      |
-- +------------------+----------------------------------+

-- 临时启用(动态修改,重启后失效)
SET GLOBAL general_log = 'ON';
SET GLOBAL general_log = 'OFF';

-- 日志输出到表(而非文件),方便 SQL 查询
SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';

-- 查询日志表
SELECT * FROM mysql.general_log ORDER BY event_time DESC LIMIT 20;
ini
# my.cnf 永久配置
[mysqld]
general_log = 0                          # 0=OFF, 1=ON(生产环境强烈建议 OFF)
general_log_file = /var/log/mysql/general.log
log_output = FILE                        # FILE, TABLE, 或 FILE,TABLE

31.2.3 警告 ​

在生产环境长期开启通用查询日志会严重降低性能(10-30% 甚至更多),因为每一条 SQL 都需要写入日志。仅在排查特定问题时临时开启,排查完毕后立即关闭。


31.3 慢查询日志 (Slow Query Log) ​

31.3.1 是什么 ​

慢查询日志记录了执行时间超过 long_query_time 阈值的 SQL 语句。它是性能优化的首要入口——找到执行最慢的查询,然后使用 EXPLAIN 分析并优化。

31.3.2 配置 ​

sql
-- 查看慢查询日志配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- +-----------------------------+----------------------------------+
-- | Variable_name               | Value                            |
-- +-----------------------------+----------------------------------+
-- | slow_query_log              | OFF                              |
-- | slow_query_log_file         | /var/lib/mysql/hostname-slow.log |
-- | long_query_time             | 10.000000                        |
-- +-----------------------------+----------------------------------+
ini
# my.cnf 推荐配置
[mysqld]
# === 慢查询日志 ===
slow_query_log = 1                          # 开启慢查询日志
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2                         # 超过 2 秒的查询
log_queries_not_using_indexes = 1           # 同时记录不使用索引的查询
log_slow_admin_statements = 1               # 同时记录慢的 DDL 语句
min_examined_row_limit = 1000               # 至少扫描 1000 行的查询才记录
log_slow_extra = ON                         # MySQL 8.0.14+: 额外信息(字节数等)
log_output = FILE                           # 输出到文件(也可以 TABLE)

31.3.3 慢查询日志格式 ​

text
# Time: 2024-01-15T10:30:45.123456Z
# User@Host: app_user[app_user] @ 192.168.1.100 [192.168.1.100]  Id: 42
# Query_time: 5.234567  Lock_time: 0.001234  Rows_sent: 100  Rows_examined: 500000
# Bytes_sent: 12345  (MySQL 8.0.14+ with log_slow_extra)
SET timestamp=1705314645;
SELECT o.*, u.name, u.email
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'shipped'
ORDER BY o.created_at DESC
LIMIT 100;

字段说明:

  • Query_time:查询执行的总时间(秒)
  • Lock_time:等待锁的时间(秒)—— 如果这个值很高,说明存在锁竞争
  • Rows_sent:返回给客户端的行数
  • Rows_examined:实际扫描的行数 —— Rows_examined >> Rows_sent 说明索引有问题
  • Bytes_sent:发送的数据量

31.3.4 慢查询日志分析工具 ​

1. mysqldumpslow(MySQL 自带)

bash
# 按查询时间排序(最慢的 10 条)
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 按出现次数排序(最多的 10 条)
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log

# 按返回行数排序
mysqldumpslow -s r -t 10 /var/log/mysql/slow.log

# 按锁等待时间排序
mysqldumpslow -s l -t 10 /var/log/mysql/slow.log

# 包含具体值的查询(不聚合)
mysqldumpslow -a -s t -t 5 /var/log/mysql/slow.log

# 按模式分组(默认行为)
mysqldumpslow -s t -t 5 /var/log/mysql/slow.log
# 输出:
# Count: 50  Time=3.45s (172s)  Lock=0.00s (0s)  Rows=1.0 (50)
#   SELECT * FROM orders WHERE user_id=N AND status='S'

2. pt-query-digest(Percona Toolkit)

pt-query-digest 远比 mysqldumpslow 强大,是生产环境分析慢查询的首选工具:

bash
# 分析慢查询日志
pt-query-digest /var/log/mysql/slow.log > slow_report.txt

# 分析最近 12 小时的慢查询
pt-query-digest --since='12h' /var/log/mysql/slow.log

# 分析到指定时间为止
pt-query-digest --until='2024-01-15 12:00:00' /var/log/mysql/slow.log

# 分析指定数据库的查询
pt-query-digest --filter '$event->{db} eq "mydb"' /var/log/mysql/slow.log

# 输出报告包含:
# - 总体统计(查询数、唯一模式数、执行时间分布)
# - 按查询时间排序的 TOP 查询
# - 每个查询的详细分析:
#   - 执行次数、总时间、平均/中位数/95%/99% 时间
#   - 执行时间分布图
#   - EXPLAIN 计划
#   - 优化建议
# - 按数据库、用户、主机统计

# 分析 processlist 快照
pt-query-digest --processlist h=localhost,u=root,p=password --interval 1 --iterations 60

# 分析 tcpdump 抓取的流量
# tcpdump -i eth0 port 3306 -s 65535 -w mysql.pcap
# pt-query-digest --type tcpdump mysql.pcap

31.3.5 慢查询日志到表 ​

sql
-- 将慢查询日志输出到 mysql.slow_log 表
SET GLOBAL log_output = 'TABLE';

-- 查询慢查询日志表
SELECT
  start_time,
  user_host,
  query_time,
  lock_time,
  rows_sent,
  rows_examined,
  CONVERT(sql_text USING utf8mb4) AS sql_text
FROM mysql.slow_log
ORDER BY query_time DESC
LIMIT 20;

-- 统计最慢的查询类型
SELECT
  LEFT(CONVERT(sql_text USING utf8mb4), 100) AS query_pattern,
  COUNT(*) AS count,
  AVG(query_time) AS avg_time,
  MAX(query_time) AS max_time
FROM mysql.slow_log
WHERE start_time >= DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY query_pattern
ORDER BY avg_time DESC
LIMIT 20;

31.4 二进制日志 (Binary Log / Binlog) ​

31.4.1 是什么 ​

二进制日志记录了**所有对数据库数据产生更改的 SQL 语句或行变更 **。它的三个主要用途:

  1. 复制(Replication):从库通过读取主库的 binlog 来复制数据
  2. Point-in-Time Recovery(PITR):恢复全量备份后通过 binlog 恢复到指定时间点
  3. 审计:追踪谁在什么时间做了什么数据变更(需配合其他审核工具)

31.4.2 三种 binlog 格式 ​

sql
-- 查看当前 binlog 格式
SHOW VARIABLES LIKE 'binlog_format';

1. STATEMENT(语句模式)

记录 SQL 语句原文。最小,但非确定性函数(NOW()、UUID()、RAND())会导致主从数据不一致。

sql
-- 假设执行:
INSERT INTO orders (user_id, created_at) VALUES (1, NOW());

-- STATEMENT 模式下 binlog 记录:
-- INSERT INTO orders (user_id, created_at) VALUES (1, NOW());
-- 问题:主从执行 NOW() 的时间不同 → 数据不一致!

2. ROW(行模式)—— 推荐

记录每一行数据变更的前后镜像。数据一致性最好,但日志量最大。

sql
-- ROW 模式下 binlog 记录(伪代码展示):
-- ### INSERT INTO `mydb`.`orders`
-- ### SET
-- ###   @1=1       (user_id)
-- ###   @2='2024-01-15 10:00:00'  (created_at,已确定的值!)
-- 问题消失:从库直接复制确切值,不执行 NOW()

3. MIXED(混合模式)

大部分语句使用 STATEMENT,当 MySQL 判断语句可能产生不一致时自动切换为 ROW。

ini
# 推荐配置
[mysqld]
log_bin = /var/log/mysql/binlog          # 开启 binlog,指定文件路径前缀
binlog_format = ROW                      # 使用 ROW 格式
binlog_expire_logs_seconds = 604800      # 7 天后自动清理(替代旧版 expire_logs_days)
max_binlog_size = 1073741824             # 1GB 后自动切换新文件
binlog_row_image = FULL                  # FULL(完整行)/ MINIMAL(仅变更列)/ NOBLOB
sync_binlog = 1                          # 每次事务提交后同步 binlog 到磁盘(1=最安全)

31.4.3 管理和查看 ​

sql
-- 查看所有 binlog 文件
SHOW BINARY LOGS;

-- 查看当前 binlog 位置
SHOW MASTER STATUS;

-- 查看 binlog 事件
SHOW BINLOG EVENTS IN 'binlog.000001' LIMIT 20;

-- 查看指定位置的 binlog 事件
SHOW BINLOG EVENTS IN 'binlog.000001' FROM 1234 LIMIT 10;

-- 手动刷新日志(关闭当前文件,开启新文件)
FLUSH LOGS;
-- 或
FLUSH BINARY LOGS;

-- 清理旧 binlog
PURGE BINARY LOGS TO 'binlog.000010';    -- 删除之前的所有日志
PURGE BINARY LOGS BEFORE '2024-06-01';   -- 删除指定日期之前的日志

-- 重置(删除所有 binlog,危险!仅测试环境使用)
RESET MASTER;

31.5 Redo Log(重做日志 / InnoDB) ​

31.5.1 是什么 ​

Redo Log 是 InnoDB 存储引擎独有的日志,记录了对数据页的物理修改。它保证事务的持久性(Durability) —— 即使 MySQL 崩溃,已提交的事务也不会丢失。

核心机制是 WAL(Write-Ahead Logging,预写日志):

修改数据页之前,先将变更记录写入 Redo Log(顺序写,很快)。即使数据页还没来得及写入磁盘,崩溃后也可以通过 Redo Log 重放恢复。

31.5.2 工作原理 ​

事务提交流程:
1. 修改 Buffer Pool 中的数据页(在内存中)
2. 将数据页的变更记录写入 Redo Log Buffer(内存)
3. COMMIT 时:将 Redo Log Buffer 刷新到磁盘的 Redo Log 文件
4. 此时事务被认为已提交(持久化保证)
5. 后续某个时机:将 Buffer Pool 中的脏页刷新到磁盘的数据文件
   (Checkpoint 机制,比步骤3晚得多)

崩溃恢复:
1. MySQL 启动时发现 Redo Log 中有已提交但数据页未落盘的事务
2. 重放 Redo Log,将数据页恢复到最新状态
3. 回滚未提交的事务
4. 数据库恢复到一致状态

31.5.3 LSN(Log Sequence Number) ​

LSN 是 Redo Log 中的单调递增序列号,用于追踪日志位置:

sql
-- 查看当前 LSN
SHOW ENGINE INNODB STATUS\G
-- 在输出中查找:
-- Log sequence number          1234567890
-- Log flushed up to            1234567890
-- Pages flushed up to          1234567800
-- Last checkpoint at           1234567000

-- 解释:
-- Log sequence number:当前日志位置(最新产生的 LSN)
-- Log flushed up to:已刷新到磁盘的 LSN
-- Pages flushed up to:数据页已刷新到磁盘的 LSN
-- Last checkpoint at:最近一次 Checkpoint 的 LSN
-- Checkpoint 之前的 Redo Log 空间可以被安全覆盖

31.5.4 配置 ​

ini
[mysqld]
# Redo Log 文件大小(每个文件的大小,单位:字节)
innodb_log_file_size = 1073741824  # 1GB(生产环境建议 1-4GB)

# Redo Log 文件组中的文件数量
innodb_log_files_in_group = 2      # 默认 2

# Redo Log 总大小 = innodb_log_file_size × innodb_log_files_in_group

# 配置建议:
# - 文件越大 → Checkpoint 频率越低 → 写性能越好 → 崩溃恢复时间越长
# - 文件越小 → Checkpoint 频繁 → 写性能下降 → 崩溃恢复快
# - 生产环境典型值:1-4 GB × 2 = 2-8 GB 总 Redo Log 空间

31.6 Undo Log(回滚日志 / InnoDB) ​

31.6.1 是什么 ​

Undo Log 记录了数据修改前的"旧版本"。它有两大用途:

  1. 事务回滚(ROLLBACK):撤销未提交事务的修改
  2. MVCC(多版本并发控制):为其他事务提供一致性快照读

31.6.2 与 Redo Log 的关系 ​

                    Redo Log                Undo Log
+-------------------------------------------------------+
| 记录内容   |  物理修改(怎么改)     | 旧版本数据(改了什么) |
| 写入方式   |  顺序写(追加)         | 随机写(回滚段)      |
| 保护对象   |  已提交事务不丢失        | 未提交事务可回滚       |
| 方向       |  前滚(重做)           | 回滚(撤销)          |
| 清理方式   |  Checkpoint 后覆盖     | Purge 线程清理        |
| 存储位置   |  ib_logfile0/1         | undo tablespace       |
+-------------------------------------------------------+
示例:UPDATE users SET balance = balance - 100 WHERE id = 1;

Redo Log 记录:
  "在 page 123, offset 456 处,将值从 1000 改为 900"
  (物理级别的页修改指令)

Undo Log 记录:
  "balance 的旧值是 1000"
  (逻辑级别的数据前像)

如果 ROLLBACK:
  → 使用 Undo Log 将 balance 恢复为 1000
  → Redo Log 也记录了这个回滚操作(保证 crash safe)

如果另一个事务在 UPDATE 前读取:
  → 通过 Undo Log 构建历史版本
  → 读到 balance = 1000(快照读)

31.6.3 Undo 表空间配置 ​

ini
[mysqld]
# Undo 表空间数量(MySQL 8.0 默认 2 个,不能更改已有表空间数量后减少)
innodb_undo_tablespaces = 2

# Undo 表空间文件路径(默认在数据目录下的 undo_001, undo_002)
innodb_undo_directory = /var/lib/mysql/

31.6.4 Undo 的两种段类型 ​

1. INSERT Undo Segment(插入撤销段)
   - 仅 INSERT 语句使用
   - 事务提交后立即可丢弃(因为新插入的行对其他事务不可见)
   
2. UPDATE Undo Segment(更新撤销段)
   - UPDATE 和 DELETE 语句使用
   - 事务提交后不能立即丢弃!
   - 原因:其他事务可能正在读取旧版本(MVCC 快照读)
   - 由后台 Purge 线程在确定没有事务需要旧版本后清理
   - 长事务会导致 Undo Log 膨胀(这就是为什么需要避免长事务!)

31.7 SHOW ENGINE INNODB STATUS ​

这是 InnoDB 引擎的"仪表盘",提供了大量运行时信息:

sql
SHOW ENGINE INNODB STATUS\G

输出包含的关键部分:

text
=====================================
2024-01-15 10:30:00 0x7f8a1c0b2700 INNODB MONITOR OUTPUT
=====================================

--- BACKGROUND THREAD ---
# 后台线程状态

--- SEMAPHORES ---
# 信号量等待(互斥锁/读写锁竞争)

--- LATEST DETECTED DEADLOCK ---
# 最近检测到的死锁详情

--- TRANSACTIONS ---
# 活跃事务列表,锁等待信息

--- FILE I/O ---
# 文件 I/O 线程统计

--- INSERT BUFFER AND ADAPTIVE HASH INDEX ---
# 插入缓冲和自适应哈希索引状态

--- LOG ---
# Redo Log 统计(LSN、Checkpoint 等)

--- BUFFER POOL AND MEMORY ---
# Buffer Pool 使用率、命中率、脏页比例

--- ROW OPERATIONS ---
# 行操作统计(读取、插入、更新、删除行数)

31.8 五种日志总结对比 ​

+------------------+---------------+------------------------+---------------------+
| 日志类型          | 存储引擎       | 主要用途                | 关键配置              |
+------------------+---------------+------------------------+---------------------+
| Error Log        | Server 层     | 调试、故障排查          | log_error            |
| General Query Log| Server 层     | 调试、临时审计          | general_log          |
| Slow Query Log   | Server 层     | 性能优化入口            | long_query_time      |
| Binary Log       | Server 层     | 复制、PITR              | binlog_format=ROW    |
| Redo Log         | InnoDB (引擎) | 崩溃恢复(持久性)       | innodb_log_file_size |
| Undo Log         | InnoDB (引擎) | 回滚 + MVCC             | innodb_undo_*        |
+------------------+---------------+------------------------+---------------------+

常见错误 ​

错误 1:在生产环境长期开启通用查询日志 ​

问题:为了排查偶尔出现的慢查询,开启了 general_log,
     但忘记关闭,几天后发现服务器负载异常升高。

症状:磁盘 I/O 飙升,写线程阻塞,大量查询排队。

解决:
  SET GLOBAL general_log = 'OFF';  -- 立即关闭
  -- 改用慢查询日志 + pt-query-digest 定位慢查询

错误 2:innodb_log_file_size 设置过小 ​

问题:在高并发写入场景(1000+ TPS)下使用默认的 48MB Redo Log,
     导致 Checkpoint 过于频繁,磁盘 I/O 成为瓶颈。

症状:
  - SHOW ENGINE INNODB STATUS 中 "pending log writes" 高
  - 写入吞吐量远低于磁盘能力
  - innodb_log_waits 状态变量持续增长

解决:
  -- 增大 Redo Log 大小(需要重启 MySQL)
  innodb_log_file_size = 2147483648  # 2GB
  
  -- 验证效果
  SHOW STATUS LIKE 'Innodb_log_waits';
  -- 理想值为 0

错误 3:binlog 和 Redo Log 的混淆 ​

常见误解:
  "binlog 已经记录了所有变更,为什么还需要 Redo Log?"

解释:
  binlog(Server 层):记录逻辑 SQL,用于复制和 PITR
  Redo Log(InnoDB 层):记录物理页修改,用于崩溃恢复
  
  binlog 不能替代 Redo Log,因为:
  1. binlog 是逻辑的(SQL 或行变更),无法用于页级别的恢复
  2. 崩溃时刻,内存中已修改但未写入 binlog 的数据需要 Redo Log 恢复
  3. 两者记录的内容和级别完全不同

错误 4:忽略慢查询日志中的 "Rows_examined" ​

问题:只关注 Query_time(查询时间),忽略了 Rows_examined 远大于 Rows_sent 的情况。

分析:
  Rows_examined = 500000, Rows_sent = 100 → 扫描 5000 行返回 1 行
  这说明索引设计有问题或者查询没有使用合适的索引

解决:
  使用 EXPLAIN 分析该查询,通常可以通过添加索引将 Rows_examined 降低几个数量级

错误 5:Undo Log 膨胀导致磁盘空间不足 ​

问题:磁盘空间告警,发现 undo tablespace 文件异常大。

原因:
  1. 有长时间未提交的事务(可能是应用 bug 导致的"悬挂"事务)
  2. Purge 线程跟不上(高并发 DELETE/UPDATE)
  
排查:
  SELECT trx_id, trx_state, trx_started,
         TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS seconds_running,
         trx_rows_modified
  FROM information_schema.INNODB_TRX
  ORDER BY trx_started;

解决:
  - 找到并终止长事务
  - 检查 innodb_purge_threads 配置
  - 重建 undo tablespace(高级操作)

本章练习 ​

练习 1:日志配置实践 ​

在新安装的 MySQL 实例上完成以下配置:

  1. 配置错误日志到独立目录
  2. 开启慢查询日志,设置阈值为 1 秒
  3. 配置 binlog 为 ROW 格式,设置 7 天自动清理
  4. 验证所有配置已生效(使用 SHOW VARIABLES)
  5. 写入配置文件而非动态设置,确保重启后保留

练习 2:慢查询日志分析 ​

  1. 创建一个大表(100 万行以上),故意执行几个慢查询
  2. 启用慢查询日志,捕获这些查询
  3. 使用 mysqldumpslow 分析慢查询日志,找出 TOP 5
  4. 使用 pt-query-digest 生成详细报告
  5. 对比两个工具的分析结果差异
  6. 针对最慢的查询,给出优化方案并实施

练习 3:Redo Log 大小对性能的影响 ​

  1. 在默认 Redo Log 大小(48MB)下,用 sysbench 执行写入压力测试,记录 TPS
  2. 将 Redo Log 增大到 1GB,重复测试
  3. 将 Redo Log 增大到 4GB,重复测试
  4. 分析 innodb_log_waits 状态变量的变化
  5. 解释 TPS 提升的原因(Checkpoint 频率与 Redo Log 大小的关系)

练习 4:Binlog 格式对比 ​

  1. 创建一个包含 UUID() 和 NOW() 调用的测试场景
  2. 分别在 STATEMENT、ROW、MIXED 三种格式下执行相同操作
  3. 使用 mysqlbinlog 查看三种格式下的日志内容差异
  4. 对比日志文件大小
  5. 分析为什么 ROW 格式能保证数据一致性

练习 5:崩溃恢复模拟(重要) ​

  1. 开启一个事务,INSERT 数据但不提交
  2. 在另一个会话中查看该事务对数据的可见性(MVCC)
  3. 使用 kill -9 模拟 MySQL 崩溃
  4. 重启 MySQL,观察错误日志中的崩溃恢复过程
  5. 验证:未提交的事务被回滚,数据一致性被保持

练习 6:综合日志监控脚本 ​

编写一个监控脚本(Shell/Python),实现:

  1. 每小时检查慢查询日志是否有新的 TOP 10 慢查询
  2. 检查错误日志中的 ERROR 级别信息并告警
  3. 检查 binlog 磁盘空间使用率
  4. 检查 Undo Log 膨胀情况(SHOW ENGINE INNODB STATUS)
  5. 生成每日日志健康报告并发送邮件

把零散知识,整理成可以反复走的路。