前言
一、错误日志
二、慢查询日志
三、查询日志
四、二进制binlog日志
五、redo log(InnoDB 引擎日志文件)
binlog 与 redolog的区别
六、Mysql 执行一条更新操作的整体流程
对于Myql来说,其所包含的文件有多种,主要有如下几种:
参数文件:存储了Mysql启动与运行时配置信息相关的属性;如 my.cnf配置文件存储了Mysql 相应的属性。
日志文件:记录了Mysql在运行时产生的日志信息,可用于对操作日志审计或恢复数据等。通常所说的日志文件有:错误日志、二进制日志文件、慢查询日志文件、查询日志文件等。
pid 文件:Mysql 实例进程的 ID 文件。
Mysql 表结构文件:用于存放表结构的定义文件。
存储引擎文件:Mysql的引擎对应的是表,每个引擎都有自己存储数据对应的文件格式。这些引擎文件存储了真正的数据与索引信息。
本文重点介绍Mysql的日志架构,因此下文着重介绍Mysql的日志文件。
笔者整理后,主要有以下几种日志文件:binlog 、redolog、error log、show query log、log。如下图所示:
存储内容:错误日志文件对MySQL的启动、运行、关闭过程进行了记录。默认为开启。
mysql> SHOW VARIABLES LIKE 'log_error';
+---------------+------------+
| Variable_name | Value |
+---------------+------------+
| log_error | ./dn02.err |
+---------------+------------+
1 row in set (0.00 sec)
如上可知:错误日志存储路径为 ./dn02.err,其中dn02为笔者主机映射域名,/usr/local/mysql/data为笔者mysql安装路径,故绝对路径为:/usr/local/mysql/data/dn02.err
重启Mysql服务器,查看错误日志如下
2019-06-30T06:16:34.170958Z 0 [Warning] [MY-010909] [Server] /usr/local/mysql/bin/mysqld: Forcing close of thread 1715 user: 'root'.
2019-06-30T06:16:35.756124Z 0 [System] [MY-010910] [Server] /usr/local/mysql/bin/mysqld: Shutdown complete (mysqld 8.0.11) MySQL Community Server - GPL.
2019-06-30T06:16:36.363776Z 0 [Warning] [MY-010915] [Server] 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.
2019-06-30T06:16:36.363923Z 0 [System] [MY-010116] [Server] /usr/local/mysql/bin/mysqld (mysqld 8.0.11) starting as process 117663
2019-06-30T06:16:36.382442Z 1 [Warning] [MY-012197] [InnoDB] InnoDB: Unable to open './gzdc/TBL_PERSON.ibd'
2019-06-30T06:16:36.382542Z 1 [Warning] [MY-012197] [InnoDB] InnoDB: Unable to open './gzdc/TBL_ORG.ibd'
2019-06-30T06:16:36.382566Z 1 [Warning] [MY-012197] [InnoDB] InnoDB: Unable to open './gzdc/EX_GONGSHANG_01V3_KYDJ.ibd'
2019-06-30T06:16:43.610735Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2019-06-30T06:16:43.636304Z 0 [System] [MY-010931] [Server] /usr/local/mysql/bin/mysqld: ready for connections. Version: '8.0.11' socket: '/tmp/mysql.sock' port: 3306 MySQL Community Server - GPL.
由于错误日志记录了Mysql启动相关的信息,因此当mysql出现与启动或配置属性等服务相关的错误时,第一个应该查看的就是这个错误日志。
存储内容:记录了查询过程中执行比较慢的SQL语句。默认为关闭。
前面提到可以通过错误日志得到一些关于数据库优化的信息,而慢查询日志 (slow_log)可帮助DBA定位可能存在问题的SQL语句,从而进行SQL语句层面的优化。
例如,可以在MySQL启动时设一个阈值,将运行时间超过该值的所有SQL语句都记录到慢查询日志文件中。DBA每天或每过一段时间对其进行检查,确认是否有SQL语句需要进行优化。
该阈值可以通过参数long-query_time来设置,默认值为10,代表 10秒。在默认情况下,MySQL数据库并不启动慢查询日志,用户需要手工将这个参数设为ON。因此该功能主要是在对SQL语句进行调优时再打开。
查看慢查询日志默认阈值如下:
mysql> SHOW VARIABLES LIKE 'long_query_time';
*************************** 1. row ***************************
Variable_name: long_query_time
Value: 10.000000
1 row in set (0.00 sec)
慢查询日志启动:
mysql> SET GLOBAL slow_query_log='on';
Query OK, 0 rows affected (0.00 sec)
Mysql 5.1后,如开启了慢查询日志可支持将对应的日志记录于slow_log表中,表结构如下图所示:
mysql> SHOW CREATE TABLE mysql.slow_log\G;
*************************** 1. row ***************************
Table: slow_log
Create Table: CREATE TABLE `slow_log` (
`start_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
`user_host` mediumtext NOT NULL,
`query_time` time(6) NOT NULL,
`lock_time` time(6) NOT NULL,
`rows_sent` int(11) NOT NULL,
`rows_examined` int(11) NOT NULL,
`db` varchar(512) NOT NULL,
`last_insert_id` int(11) NOT NULL,
`insert_id` int(11) NOT NULL,
`server_id` int(10) unsigned NOT NULL,
`sql_text` mediumblob NOT NULL,
`thread_id` bigint(21) unsigned NOT NULL
) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log'
1 row in set (0.25 sec)
但是,慢查询默认的日志还是记录于文件中,如下所示:
mysql> SHOW VARIABLES LIKE 'log_output'\G;
*************************** 1. row ***************************
Variable_name: log_output
Value: FILE
1 row in set (0.00 sec)
修改成存储到表:
mysql> SET GLOBAL log_output='TABLE';
测试:
mysql> select sleep (11)\G;
*************************** 1. row ***************************
sleep (11): 0
1 row in set (11.00 sec)
这条查询语句执行时间超过10秒,按理来说会被记录到slow_log 慢查询日志中。
验证:
mysql> SELECT * FROM mysql.slow_log\G;
*************************** 1. row ***************************
start_time: 2019-06-30 15:19:50.519724
user_host: root[root] @ localhost []
query_time: 00:00:11.000336
lock_time: 00:00:00.000000
rows_sent: 1
rows_examined: 0
db:
last_insert_id: 0
insert_id: 0
server_id: 1
sql_text: select sleep (11)
thread_id: 14
1 row in set (0.00 sec)
存储内容:记录了所有对数据库的请求,无论执行请求是否得到正确结果。默认为关闭。
也可跟慢查询日志一样将记录信息记录到表中。
mysql> SHOW VARIABLES LIKE '%general_log%'\G;
*************************** 1. row ***************************
Variable_name: general_log
Value: OFF
*************************** 2. row ***************************
Variable_name: general_log_file
Value: /usr/local/mysql/data/dn02.log
2 rows in set (0.01 sec)
SET GLOBAL general_log='on';
注:因为在前面设置了log存储到表中,因此所有的日志便直接输出到对应的表中了;
开启后没过几分钟便记录下几百条数据,部分样例如下:
*************************** 231. row ***************************
event_time: 2019-06-30 15:42:20.242534
user_host: smartbi[smartbi] @ dn02.bmsoft.com.cn [10.194.186.118]
thread_id: 8
server_id: 1
command_type: Query
argument: SET autocommit=1
*************************** 232. row ***************************
event_time: 2019-06-30 15:42:20.945496
user_host: root[root] @ localhost []
thread_id: 14
server_id: 1
command_type: Query
argument: select * from general_log
232 rows in set (0.01 sec)
测试完,为了减小数据频繁操作,还是乖乖把它关了为好。
mysql> SET GLOBAL general_log='off';
Query OK, 0 rows affected (0.00 sec)
存储内容:该日志记录了对Mysql执行更新的所有操作,例如 update/delete等,有一点需要注意的是,该记录原则是执行了更新语句便会进入记录,如里执行update操作,但实际没有发生数据的更新也一样会被记录进来。
此外,二进制日志还包括了执行数据库更改操作的时间等其他额外信息。总的来说,二进制日志主要有以下几种作用。
在默认情况下,二进制日志并不是在每次写的时候同步到磁盘(用户可以理解成缓冲写)。
因此,当数据库所在操作系统发生宕机时,可能会有最后一部分数据没有写入二进制日志文件中,这会给恢复和复制带来问题。解决这一点可以引入redolog日志。
mysql> update test.user_t set name='Hadoop' where id=1;
Query OK, 1 row affected (0.08 sec)
由上述运行结果可知,其实并没有数据发生更新;查看目前该更新操作记录的binlog文件名
mysql> show master status\G;
*************************** 1. row ***************************
File: binlog.000017
Position: 485
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
binlog日志记录于 binlog.000017;其中485为文件大小为
-rw-r----- 1 mysql mysql 485 Jun 30 16:51 binlog.000016
注:binlog.index 中记录了这些归档日志对应的索引名(简单理解为文件名);
发生的修改后的日志文件如下:
mysql> SHOW BINLOG EVENTS IN 'binlog.000017' \G ;
*************************** 1. row ***************************
Log_name: binlog.000017
Pos: 4
Event_type: Format_desc
Server_id: 1
End_log_pos: 124
Info: Server ver: 8.0.11, Binlog ver: 4
*************************** 2. row ***************************
Log_name: binlog.000017
Pos: 124
Event_type: Previous_gtids
Server_id: 1
End_log_pos: 155
Info:
*************************** 3. row ***************************
Log_name: binlog.000017
Pos: 155
Event_type: Anonymous_Gtid
Server_id: 1
End_log_pos: 230
Info: SET @@SESSION.GTID_NEXT= 'ANONYMOUS'
*************************** 4. row ***************************
Log_name: binlog.000017
Pos: 230
Event_type: Query
Server_id: 1
End_log_pos: 310
Info: BEGIN
*************************** 5. row ***************************
Log_name: binlog.000017
Pos: 310
Event_type: Table_map
Server_id: 1
End_log_pos: 375
Info: table_id: 62 (test.user_t)
*************************** 6. row ***************************
Log_name: binlog.000017
Pos: 375
Event_type: Update_rows
Server_id: 1
End_log_pos: 456
Info: table_id: 62 flags: STMT_END_F
*************************** 7. row ***************************
Log_name: binlog.000017
Pos: 456
Event_type: Xid
Server_id: 1
End_log_pos: 487
Info: COMMIT /* xid=8 */
7 rows in set (0.00 sec)
[root@dn02 data]# mysqlbinlog --start-position=1 binlog.000017
...
#190630 17:02:44 server id 1 end_log_pos 375 CRC32 0xf88cd5eb Table_map: `test`.`user_t` mapped to number 62
# at 375
#190630 17:02:44 server id 1 end_log_pos 456 CRC32 0x13626f55 Update_rows: table id 62 flags: STMT_END_F
....
[root@dn02 data]#
mysql> SHOW VARIABLES LIKE '%binlog%';
+--------------------------------------------+----------------------+
| Variable_name | Value |
+--------------------------------------------+----------------------+
| binlog_cache_size | 32768 |
| binlog_checksum | CRC32 |
| binlog_direct_non_transactional_updates | OFF |
| binlog_error_action | ABORT_SERVER |
| binlog_expire_logs_seconds | 2592000 |
| binlog_format | ROW |
| binlog_group_commit_sync_delay | 0 |
| binlog_group_commit_sync_no_delay_count | 0 |
| binlog_gtid_simple_recovery | ON |
| binlog_max_flush_queue_time | 0 |
| binlog_order_commits | ON |
| binlog_row_image | FULL |
| binlog_row_metadata | MINIMAL |
| binlog_row_value_options | |
| binlog_rows_query_log_events | OFF |
| binlog_stmt_cache_size | 32768 |
| binlog_transaction_dependency_history_size | 25000 |
| binlog_transaction_dependency_tracking | COMMIT_ORDER |
| innodb_api_enable_binlog | OFF |
| log_statements_unsafe_for_binlog | ON |
| max_binlog_cache_size | 18446744073709547520 |
| max_binlog_size | 1073741824 |
| max_binlog_stmt_cache_size | 18446744073709547520 |
| sync_binlog | 1 |
+--------------------------------------------+----------------------+
24 rows in set (0.01 sec)
如:binlog_expire_logs_seconds | 2592000 这个设置意思是binlog.xxx日志保存一个月的记录,也就是说可以通过其恢复一个月内任何时间内对数据所做的处理,包含删除修改等更新操作。
存储内容:记录了 Mysql 中实际被修改的数据。其主要有以下特点:
mysql> update T set c=c+1 where ID=2;
在上一篇文章中,我们知道Mysql中执行一条查询语句,其执行流程图如下图:
通过上图可看出,对于redolog日志是先写入然后进入prepare阶段,然后再写入binlog,两个都写成功后再进行一起提交,对于redolog从专业术语上来说,这就是redolog的两阶段提交。
两阶段提交主要是为了后期当通过binlog对数据进行恢复时,能确保binlog与redolog对应的数据是一致的。
详细学习redolog与binlog 推荐阅读极客时间《Mysql常见的6个日志问题》一文
注:参考极客时间《日志系统:一条SQL更新语句是如何执行的?》
Mysql技术内幕InnoDB存储引擎