MySQL日志详解
一、 mysql日志
日志是 mysql 数据库的重要组成部分,记录着数据库运行期间各种状态信息。mysql日志主要包括错误日志、二进制日志、查询日志、慢查询日志、事务日志(redo log和undo log)几大类。
逻辑日志和物理日志
首先按照日志的记录方式分为:逻辑日志和物理日志
- 逻辑日志:可以简单理解为记录的就是sql语句 。
- 物理日志:mysql 数据最终是保存在数据页中的,物理日志记录的就是数据页变更 。
binlog日志和回滚日志undo log日志都属于逻辑日志,记录的是sql语句,而redo log 重做日志属于物理日志记录的是数据页的变更。
错误日志
错误日志记录mysqld启动、停止和服务器运行过程中发生的任何严重的错误信息。
设置错误日志文件地址:
[mysqld]
log-error = "/home/chenyubo/www/logs/mysql.error.log"
若不指定文件名,默认文件名为hostname.err;若不指定目录,默认目录为DATADIR(数据目录)。
二进制日志
即binlog,记录所有的DDL语句和DML语句,但不包括查询语句。二进制日志的格式有三种:基于语句的格式(STATEMENNT)、基于行的格式(ROW)和混合模式(MIXED)。
1、binlog 使用场景
binlog 的主要使用场景有两个,分别是 主从复制 和 数据恢复 。
-
主从复制 :在 Master 端开启 binlog ,然后将 binlog发送到各个 Slave 端, Slave 端重放 binlog 从而达到主从数据一致。
-
数据恢复 :通过使用 mysqlbinlog 工具来恢复数据。
2 、binlog 记录方式
-
主从复制 :在 Master 端开启 binlog ,然后将 binlog发送到各个 Slave 端, Slave 端重放 binlog 从而达到主从数据一致。
-
数据恢复 :通过使用 mysqlbinlog 工具来恢复数据。
-
2 、binlog 记录方式
-
binlog 用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。binlog 是 mysql的逻辑日志,并且由 Server 层进行记录,使用任何存储引擎的 mysql 数据库都会记录 binlog 日志。
-
binlog 是通过追加的方式进行写入的,可以通过max_binlog_size 参数设置每个 binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
3、binlog 日志格式
binlog 日志有三种格式,分别为 statment、 row 和 mixed。
在 MySQL 5.7.7之前,默认的格式是STATEMENT,MySQL 5.7.7之后,默认值是ROW。日志格式通过binlog-format指定。
statment
基于SQL 语句的复制( statement-based replication, SBR ),每一条会修改数据的sql语句会记录到binlog 中 。
- 优点:不需要记录每一行的变化,减少了 binlog 日志量,节约了 IO , 从而提高了性能;
- 缺点:在某些情况下会导致主从数据不一致,比如执行sysdate() 、 slepp() 等 。
row
基于行的复制(row-based replication, RBR ),不记录每条sql语句的上下文信息,仅需记录哪条数据被修改了 。
- 优点:不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题 ;
- 缺点:会产生大量的日志,尤其是
alter table
的时候会让日志暴涨
mixed
基于STATMENT 和 ROW 两种模式的混合复制(mixed-based replication, MBR ),一般的复制使用STATEMENT 模式保存 binlog ,对于 STATEMENT 模式无法复制的操作使用 ROW 模式保存 binlog
设置二进制日志文件地址(log-bin)和日志格式(binlog_format):
[mysqld]
log-bin = "binlog/binlog"
binlog_format=row
# binlog_format=statement
# binlog_format=mixed
若不指定文件名,默认文件名为hostname-bin.000001;若不指定目录,默认目录为DATADIR(数据目录)。
若要只记录部分数据库的二进制日志,可指定binlog-do-db参数:
[mysqld]
binlog-do-db = didi
binlog-do-db = letv
若要不记录部分数据库的二进制日志,可指定binlog-ignore-db参数:
[mysqld]
binlog-ignore-db = didi
删除binlog日志有四种方式,分别为:
1、使用reset master命令,该命令删除所有的binlog日志,新日志编号从000001开始。
mysql> reset master;
2、使用purge master logs to 'mysql-bin.00000x'命令,该命令删除'00000x'编号之前所有的日志。
mysql> purge master logs to 'mysql-bin.000006';
3、使用purge master logs before 'yyyy-mm-dd hh24:mi:ss'命令,该命令删除日期为'yyyy-mm-dd hh24:mi:ss'之前所产生的所有与日志。
mysql> purge master logs before '2020-07-10 12:12:12';
4、设置expire_logs_days参数,此参数表示日志的过期天数。过了指定的天数后日志将会被自动删除。
[mysqld]
expire_logs_days = 3
查询日志
查询日志记录了客户端执行的所有语句。二进制日志和查询不同的地方是,前者不包含查询数据的语句。
查询日志可以设置为保存在文件中或表中,可用log-output参数指定保存的位置:
[mysqld]
log-output = table
# log-output = file
# log-output = none
# log-output = table,none
log-output的可选值为table,file和none的任意组合,但none的优先级较高,若指定了none,则不保存在表和文件中。
启用查询日志可用general-log参数,并用general-log-file指定路径:
[mysqld]
# 启用查询日志
general-log = 1
# 关闭查询日志
# genera-log = 0
# 查询日志路径
general-log-file = "/home/chenyubo/www/logs/mysql.general.log"
若不指定文件名,默认文件名为hostname.log;若不指定目录,默认目录为DATADIR(数据目录)。
慢查询日志
慢查询日志记录所有执行时间超过long_query_time(单位为秒,精度可以到微妙)且记录数不小于min_examined_row_limit的所有SQL语句。
long_query_time默认为10s。但是管理语句和不使用索引查询的语句不会记录到慢查询日志。其中,管理语句包括:alter table,analyze talbe,check table,create table,create index,drop index,optimize table和repaire table。
如果要监控此两类语句,可分别通过设置log-slow-admin-statement参数和log_queries_not_using_indexes参数进行控制。
慢查询日志默认是关闭的,可用slow_query_log参数打开慢查询日志,并用slow_query_log_file指定日志路径。
在这其中,我们重点需要关注的是 binlog (主从同步 ) redo log(重做日志) undo log(回滚日志),接下来详细介绍这三种日志。
[mysqld]
# 打开慢查询日志
slow_query_log = 1
# 关闭慢查询日志
# slow_query_log = 0
# 设置慢查询阈值
long_query_time = 3
# 设置慢查询日志路径
slow_query_log_file = "/home/chenyubo/www/logs/mysql.slow.log"
如果慢查询日志很多,可使用mysqldumpslow工具对慢查询日志进行分类汇总。
事务日志
undo log 日志介绍
1 、undo log 使用场景
数据库事务四大特性中有一个是原子性 ,具体来说就是原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。
实际上, 原子性底层就是通过 undo log 实现的。undo log主要记录了数据的逻辑变化,比如一条 INSERT 语句,对应一条DELETE 的 undo log ,对于每个 UPDATE 语句,对应一条相反的 UPDATE 的 undo log ,这样在发生错误时,就能回滚到事务之前的数据状态。
同时, undo log 也是 MVCC(多版本并发控制)实现的关键。
redo log 日志介绍
为什么需要redo log
我们都知道,事务的四大特性里面有一个是持久性,具体来说就是只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态。那么mysql是如何保证一致性的呢?最简单的做法是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中。但是这么做会有严重的性能问题,主要体现在两个方面:
- 因为Innodb是以页为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,太浪费资源了!
- 一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差!
因此mysql设计了redo log,具体来说就是只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序IO)。