MySQL 日志类问题

一、常用的MySQL日志概览

日志名称 说明
错误日志 error_log 记录MySQL在启动、运行、停止时出现的问题
常规日志 general_log 记录所有客户端发送到MySQL服务端的请求
慢查询日志 slow_query_log 记录慢查询SQL
二进制日志 binary_log 记录所有的有效数据修改
中继日志 relay_log 用于主从复制,临时存储从主库同步的二进制日志

 

二、错误日志 error_log

1、获取错误日志相关设置
mysql> SHOW VARIABLES LIKE 'log_error%';
+----------------------------+----------------------------------------+
| Variable_name              | Value                                  |
+----------------------------+----------------------------------------+
| log_error                  | stderr                                 |
| log_error_services         | log_filter_internal; log_sink_internal |
| log_error_suppression_list |                                        |
| log_error_verbosity        | 2                                      |
+----------------------------+----------------------------------------+
4 rows in set (0.00 sec)

mysql> 
(1)log_error

log_error 参数定义了错误日志的存储路径,如果没有设置该值,MySQL会将错误日志保存在数据目录下的 “主机名.err” 文件。

(2)log_error_verbosity

该参数在5.7及8.0版本中存在,在5.6版本中该参数名称为“log_warnings”。

该参数为记录错误日志级别,有三个可选值

参数值 具体记录什么级别的日志
1 error message
2 error message、warning message
3 error message、warning message、note message
(3)log_error_services

MySQL8.0版本新增参数。该参数如果不额外设置,和5.7版本体验是一样的,但如果单独设置,就可以自己决定使用什么错误日志组件。

可以使用自己写的,也可以使用MySQL官方提供的。其实就是MySQL允许用户通过自定义日志组件来记录自己想要的错误。

# 参数设置格式
log_error_services=[日志服务组件1; 日志服务组件2]
#查看当前设置
mysql> show variables like 'log_error_services';
+--------------------+----------------------------------------+
| Variable_name      | Value                                  |
+--------------------+----------------------------------------+
| log_error_services | log_filter_internal; log_sink_internal |
+--------------------+----------------------------------------+
1 row in set (0.00 sec)

mysql> 

当前MySQL官方提供的错误日志组件:

组件名称 作用
log_filter_internal 默认的日志过滤组件,依赖log_error_verbosity参数
log_sink_internal 默认的日志输出组件,依赖log_error参数
log_sink_json 将错误日志输出到json文件
log_sink_syseventlog 将错误日志输出到系统日志文件
2、错误日志的使用场景

(1)MySQL启动、停止、重启等过程中,产生的错误信息来进行排错

(2)添加或修改参数配置后,重启MySQL失败,查看错误日志来排错

 

三、常规日志 general_log

1、概述

记录了客户端从与MySQL建立连接开始,到断开连接的时间内,由客户端发送到MySQL服务器端的所有请求信息。

不论请求是否被成功执行,都会被记录在常规日志中。

2、设置常规日志
# 获取常规日志当前设置
mysql> show variables like 'general_log';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| general_log   | OFF   |
+---------------+-------+
1 row in set (0.00 sec)


# 获取常规日志目录设置
mysql> show variables like 'general_log_file';
+------------------+---------------------------------+
| Variable_name    | Value                           |
+------------------+---------------------------------+
| general_log_file | /var/lib/mysql/72b7d0258d58.log |
+------------------+---------------------------------+
1 row in set (0.00 sec)

# 获取常规日志当前设置存储方式,有FILE、TABLE、NONE,默认为FILE
mysql> show variables like 'log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output    | FILE  |
+---------------+-------+
1 row in set (0.00 sec)

在MySQL8.0 中,可以通过set persist来对参数进行持久化设置。与set sessionset global不同之处在于,通过 set persist 设置的参数,即使重启MySQL,参数仍然有效。

但值得注意的是,该日志因为记录了从客户端连接到结束内所有操作,所以在短时间内就可能大量日志,占用大量存储空间。因此平常时,要把它关掉。

3、使用场景举例

明明MySQL没有报错,但数据就是没有修改成功,这时就可以通过该日志来进行分析。

 

四、慢查询日志 slow_query_log

1、概述

MySQL会将执行成功并符合条件的查询 记录到日志中。

2、使用场景

通过慢查询日志,我们可以找到需要优化的SQL。

3、慢查询日志相关参数
# 查看当前是否打开了慢查询日志
mysql> show variables like 'slow_query_log';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | OFF   |
+----------------+-------+
1 row in set (0.00 sec)

# 查看当前设置慢查询日志存储在哪里
mysql> show variables like 'slow_query_log_file';
+---------------------+--------------------------------------+
| Variable_name       | Value                                |
+---------------------+--------------------------------------+
| slow_query_log_file | /var/lib/mysql/72b7d0258d58-slow.log |
+---------------------+--------------------------------------+
1 row in set (0.00 sec)

# 超过多少秒,就记录SQL到慢查询日志
mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)

# 是否把所有没有使用索引的SQL记录到慢查询日志中
mysql> show variables like 'log_queries_not_using_indexes';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | OFF   |
+-------------------------------+-------+
1 row in set (0.00 sec)

说明:如果设置了log_queries_not_using_indexes为on,则记录所有没有使用索引的SQL到慢查询日志中,并且被记录的SQL没有超时时间的限制,只要没有使用索引,都会被记录下来。

 

五、二进制日志 binlog

1、概述

二进制日志中记录了所有对数据库中数据的修改。

2、二进制的使用场景

(1)基于时间点的备份和恢复

(2)由于误操作删除或修改了数据,也可以利用二进制日志反向恢复

(3)实现MySQL高可用架构的基础

3、二进制日志相关参数
# 二进制日志开闭状态
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+
1 row in set (0.00 sec)

# 二进制文件路径
mysql> show variables like 'log_bin_basename';
+------------------+-----------------------+
| Variable_name    | Value                 |
+------------------+-----------------------+
| log_bin_basename | /var/lib/mysql/binlog |
+------------------+-----------------------+
1 row in set (0.00 sec)

# 二进制日志格式,有ROW、STATEMENT、MIXED三种值,推荐设置为ROW
mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.00 sec)

# 在binlog_format设置为row时,该参数生效,参数值有FUll、MINIMAL、NOBLOB
mysql> show variables like 'binlog_row_image';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| binlog_row_image | FULL  |
+------------------+-------+
1 row in set (0.00 sec)


# 当binlog_format为row时,设置记录原本执行的SQL到二进制日志,方便我们查看,推荐为on
mysql> show variables like 'binlog_rows_query_log_events';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| binlog_rows_query_log_events | OFF   |
+------------------------------+-------+
1 row in set (0.00 sec)

# 主从复制时使用,设置为on时会在slave上记录同步过来的二进制日志
mysql> show variables like 'log_slave_updates';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| log_slave_updates | ON    |
+-------------------+-------+
1 row in set (0.00 sec)

# 控制MySQL如何刷新二进制日志到磁盘,设置为1时,写一次刷新一次,设置为0时,MySQL将不会主动刷新,推荐设为1,可以保证MySQL服务宕机日志记录也不会丢失。
mysql> show variables like 'sync_binlog';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog   | 1     |
+---------------+-------+
1 row in set (0.00 sec)

# 查看某个二进制文件
mysqlbinlog --no-defaults -vv --base64-output=DECODE-ROWS  binlog.000003

说明:

上面通过log_bin_basename得到二进制文件路径是/var/lib/mysql/binlog,那么实际的bninlog日志就应该在/var/lib/mysql路径下,该路径下一定有binlog.xx这种文件。请看下面这张图:

上面参数binlog_row_image设置为row时,会将每一条记录都记录在二进制日志里面,而设置为MINIMAL时,则只会记录符合条件的记录修改。

而且如果我们查看某个二进制文件会发现,其中是以具体的id和值来体现的,并不是我们实际操作的SQL,它长这个样子:

# 实际操作的SQL语句是:
update inventory set num = 88 where product_id = 1001 and warehouse_id = 2;
# 该条语句操作的数据库是test_80。

# 二进制日志中该条SQL语句的体现
/*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/;
BEGIN
/*!*/;
# at 322
#210818 13:09:11 server id 1  end_log_pos 383 CRC32 0x6ad5c0d4  Table_map: `test_80`.`inventory` mapped to number 110
# at 383
#210818 13:09:11 server id 1  end_log_pos 429 CRC32 0xc5170258  Update_rows: table id 110 flags: STMT_END_F
### UPDATE `test_80`.`inventory`
### WHERE
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
### SET
###   @4=88 /* INT meta=0 nullable=1 is_null=0 */
# at 429
#210818 13:09:11 server id 1  end_log_pos 460 CRC32 0x9640e2a8  Xid = 1035
COMMIT/*!*/;

注意:如果想让二进制日志记录的就是我们实际操作的SQL,我们应该怎么做呢?

方式一:把参数binlog_format的值设置为STATEMENT

但这种方式在主从复制中是不被推荐的,会非常不安全

方式二:把binlog_rows_query_log_events参数设置为on

这种方式是被推荐的。

从下面可以清除的看到我们实际执行的SQL

update inventory set num = 188 where product_id = 1001 and warehouse_id = 2
BEGIN
/*!*/;
# at 322
#210818 13:21:53 server id 1  end_log_pos 421 CRC32 0xa790db6c  Rows_query
# update inventory set num = 188 where product_id = 1001 and warehouse_id = 2
# at 421
#210818 13:21:53 server id 1  end_log_pos 482 CRC32 0x8cf12014  Table_map: `test_80`.`inventory` mapped to number 110
# at 482
#210818 13:21:53 server id 1  end_log_pos 528 CRC32 0x11d132e9  Update_rows: table id 110 flags: STMT_END_F
### UPDATE `test_80`.`inventory`
### WHERE
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
### SET
###   @4=188 /* INT meta=0 nullable=1 is_null=0 */
# at 528
#210818 13:21:53 server id 1  end_log_pos 559 CRC32 0xedbcced1  Xid = 1039
COMMIT/*!*/;
4、定期清理MySQL二进制日志
方式一:

我们可以通过设置expire_logs_days来定期清理过期的二进制日志。

方式二:
# 手动执行命令
purge binary logs to 'mysql-bin.010';

该命令可以把mysql-bin.001 到mysql-bin.009的二进制日志都删除掉。

方式三:
# 手动执行命令
purge binary logs before '2021-03-01 22:00:05';

该命令可以把在2021-03-01 22:00:05之前的二进制日志都删除掉。

 

六、中继日志 relay_log

1、概述

只存在于主从复制的slave上,它的作用是临时记录从主服务器同步的二进制日志。

2、重要参数
# 中继日志存放路径,如果不指定,将以主机名-relay-bin名称存储在数据目录,建议使用时要手动设置一下目录,不能像我这样不设置
mysql> show variables like 'relay_log';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| relay_log     | 72b7d0258d58-relay-bin |
+---------------+------------------------+
1 row in set (0.00 sec)

# 设置是否自动清理中继日志,设置为on时,如果中继日志中的记录已经被应用了,则会对relay_log自动清理
mysql> show variables like 'relay_log_purge';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| relay_log_purge | ON    |
+-----------------+-------+
1 row in set (0.00 sec)