首页 > 数据库 > 数据库开发技术 > 细说MySQL的日志
mysql的日志是其重要的组成部分。日志文件记录mysql数据运行期间发生变化,跟mysql的许多重要功能息息相关,比如:mysql奔溃恢复,回滚,主从同步等功能
MySQL 常见的七种日志文件:
重做日志(redo log)回滚日志(undo log)二进制日志(binlog)错误日志(errorlog)慢查询日志(slow query log)一般查询日志(general log)中继日志(relay log)
其中
重做日志和回滚日志与事务操作息息相关
二进制日志也与中继日志通常用于主从复制
错误日志是记录启动、运行或停止mysqld时出现的问题
慢查询日志经常用于数据库性能调优
下面我们逐个了解下每种的日志的介绍与使用
MySQL的错误信息是在data目录下的
错误日志本身所定义的内容本身是可以定义的
编辑配置文件,定义错误日志:
log-error=/path/to/xx.err #定义是否启动错误日志的功能log-warnings={1|0} #定义是否将警告信息也记录在错误日志中
默认情况下错误日志也记录以下几个方面的消息:
1、服务器启动和关闭过程中的信息
未必是错误信息,比如mysql是如何去初始化存储引擎的过程记录在错误日志里等等
2、服务器运行过程中的错误信息
比如sock文件找不到,无法加载mysql数据库的数据文件,如果忘记初始化mysql或data dir路径找不到,或权限不正确等,都会记录在此
3、事件调度器运行一个事件时产生的信息
一旦mysql调度启动一个计划任务的时候,它也会将相关信息记录在错误日志中
4、在从服务器上启动从服务器进程时产生的信息
在复制环境下,从服务器进程的信息也会被记录进错误日
查询日志一般情况下mysql是没有启用的,因为mysql本身为关系型数据库,用户连接进数据库的时候,用户的一切行为 增删查改 都会生成查询日志 。
因此都会产生日志,在并发操作非常多的场景下,查询信息会非常多,那么如果都记录下来会导致IO非常大 影响mysql性能,因此如果不是在调试环境下,是不建议开启查询日志功能的
编辑 my.cnf,修改 general-log 参数为 1,同时设定 log-output 参数(日志输出类型)和 general_log_file 参数(查询日志路径)
log-output=FILEgeneral-log=1general_log_file="filename.log"
慢查询日志中记录了时长,明确说明了哪个时间段执行和结束,中间执行了多长时间
对于非常繁忙的服务器,如果中途出现了查询速度非常慢的场景中,通常需要启动慢查询日志功能,慢查询日志对性能的影响微乎其微,但是可以详细记录了服务器上的慢查询,因此可以去定位服务器的瓶颈
编辑 my.cnf ,设置 log_slow_queries 参数为 1,同时设定 log-output 参数(日志输出类型)、slow-query-log_file 参数(慢查询日志路径)和 long_query_time 参数:
log-output=FILElog_slow_queries=1 //MySQL 5.6将此参数修改为了slow_query_logslow_query_log_file="filename.log"long_query_time=10 //慢查的时长单位为秒,可以精确到小数点后6位(微秒)
log_slow_queries :表示是否开启慢查询日志,5.6以前的版本使用此参数指定是否开启慢查询日志,5.6以后的版本使用slow_query_log取代此参数,如果你使用的mysql版本刚好是5.5,那么你可以看到这两个参数同时存在,此时我们不用同时设置它们,设置这两个参数中的任何一个,另一个也会自动保持一致。
log_output : 表示当慢查询日志开启以后,以哪种方式存放,log_output可以设置为4种值,"FILE"、"TABLE"、"FILE,TABLE"、"NONE"。
此值为"FILE"表示慢查询日志存放于指定的文件中此值为"TABLE"表示慢查询日志存放于mysql库的slow_log表中此值为"FILE,TABLE"表示将慢查询日志同时存放于指定的文件与slow_log表中,一般不会进行这样的设置,因为这样会徒增很多IO压力,如果开启,建议设置为"table"此值为"NONE"时表示不记录查询日志,即使slow_query_log设置为ON,如果log_output设置为NONE,也不会记录慢查询日志
其实,log_output不止用于控制慢查询日志的输出,查询日志的输出也是由此参数进行控制,也就是说,log_output设置为file,就表示查询日志和慢查询日志都存放到对应的文件中,设置为table,查询日志和慢查询日志就都存放在对应的数据库表中。
slow_query_log :表示是否开启慢查询日志,此参数与log_slow_queries的作用没有区别,5.6以后的版本使用此参数替代log_slow_queries。
slow_query_log_file :当使用文件存储慢查询日志时(log_output设置为"FILE"或者"FILE,TABLE"时),指定慢查询日志存储于哪个日志文件中,默认的慢查询日志文件名为"主机名-slow.log",慢查询日志的位置为datadir参数所对应的目录位置,一般情况下为 /var/lib/mysql
long_query_time :表示"多长时间的查询"被认定为"慢查询",此值得默认值为10秒,表示超过10秒的查询被认定为慢查询。
mysql自带了对慢查询日志的统计分析工具,mysqldumpslow,通过mysqldumpslow命令我们可以更加方便的从不同的维度对慢日志进行排序、查找、统计。
Mysqldumpslow –s r slow.log -s选项代表排序,根据什么排序取决于-s选项后添加的参数
常用参数介绍
c: 执行计数l: 锁定时间r: 返回记录t: 执行时间al:平均锁定时间ar:平均返回记录数at:平均执行时间
还可以使用-t选项,指明只查看多少条统计
mysqldumpslow 还有一些其他选项,可以使用mysqldumpslow --help查看
二进制日志记录 MySQL 数据库中所有与更新相关的操作,即二进制日志记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但是不包括数据查询语句。主要用于时间点恢复(备份恢复)和主从复制。
MariaDB/MySQL默认没有启动二进制日志,要启用二进制日志使用 --log-bin=[on|off|file_name] 选项指定,如果没有给定file_name,则默认为datadir下的主机名加"-bin",并在后面跟上一串数字表示日志序列号,如果给定的日志文件中包含了后缀(logname.suffix)将忽略后缀部分。
mysqld还创建一个二进制日志索引文件,当二进制日志文件滚动的时候会向该文件中写入对应的信息。所以该文件包含所有使用的二进制日志文件的文件名。默认情况下该文件与二进制日志文件的文件名相同,扩展名为'.index’。


删除二进制日志有几种方法。不管哪种方法,都会将删除后的信息同步到二进制index文件中。
1.reset master将会删除所有日志,并让日志文件重新从000001开始。
reset master;2.PURGE { BINARY | MASTER } LOGS { TO 'log_name' | BEFORE datetime_expr }
purge master logs to "binlog_name.00000X" 将会清空00000X之前的所有日志文件。例如删除000006之前的日志文件。3.使用--expire_logs_days=N选项指定过了多少天日志自动过期清空。
二进制日志相关的变量
log_bin = {on | off | base_name} #指定是否启用记录二进制日志或者指定一个日志路径(路径不能加.否则.后的被忽略)sql_log_bin ={ on | off } #指定是否启用记录二进制日志,只有在log_bin开启的时候才有效expire_logs_days = #指定自动删除二进制日志的时间,即日志过期时间log_bin_index = #指定mysql-bin.index文件的路径binlog_format = { mixed | row | statement } #指定二进制日志基于什么模式记录binlog_rows_query_log_events = { 1|0 } # MySQL5.6.2添加了该变量,当binlog format为row时,默认不会记录row对应的SQL语句,设置为1或其他true布尔值时会记录,但需要使用mysqlbinlog -v查看,这些语句是被注释的,恢复时不会被执行。max_binlog_size = #指定二进制日志文件最大值,超出指定值将自动滚动。但由于事务不会跨文件,所以并不一定总是精确。max_binlog_cache_size = #指定二进制日志缓存最大大小,硬限制。默认4G,够大了,建议不要改
二进制日志有3种记录方式,三种方式如下:
statement模式:记录对数据库做出修改的语句,比如,update A set test='test',如果使用statement模式,那么这条update语句将会被记录到二进制日志中。
优点是binlog日志量少,IO压力小,性能较高缺点是为了能够尽量的完全一致的还原操作,除了记录语句本身以外,可能还需要记录一些相关的信息,而且,在使用一些特定的函数时,并不能保证恢复操作与记录时完全一致。
row模式:记录对数据库做出修改的语句所影响到的数据行以及这些行的修改,比如,update A set test='test',如果使用row模式,那么这条update语句所影响到的行所对应的修改,将会记录到binlog中,比如,A表中有1000条数据,那么当执行这条update语句以后,由于1000条数据都会被修改,所以会有1000行数据被记录到二进制日志中,以及它们是怎样被修改的。
优点是能够完全的还原或者复制日志被记录时的操作缺点是记录日志量较大,IO压力大,性能消耗较大
mixed模式:混合使用上述两种模式,一般的语句使用statment方式进行保存,如果遇到一些特殊的函数,则使用row模式进行记录,这种记录方式被称之为mixed,看上去这种方式似乎比较美好,但是在生产环境中,为了保险起见,一般会使用row模式。
在配置文件修改参数:
[]log-bin=mysql-binbinlog_format=”STATEMENT”运行时在线修改:调整为row模式mysql> set global binlog_format = ROW;
二进制日志可以使用mysqlbinlog命令查看
常用的几个选项:
-d,--database=name:只查看指定数据库的日志操作-o,--offset=#:忽略掉日志中的前n个操作命令-r,--result-file=name:将输出的日志信息输出到指定的文件中,使用重定向也一样可以。-s,--short-form:显示简单格式的日志,只记录一些普通的语句,会省略掉一些额外的信息如位置信息和时间信息以及基于行的日志。可以用来调试,生产环境千万不可使用--set-charset=char_name:在输出日志信息到文件中时,在文件第一行加上set names char_name--start-datetime,--stop-datetime:指定输出开始时间和结束时间内的所有日志信息--start-position=#,--stop-position=#:指定输出开始位置和结束位置内的所有日志信息-v,-vv:显示更详细信息,基于row的日志默认不会显示出来,此时使用-v或-vv可以查看
中继日志用于主从复制架构中的从服务器上,从服务器的 slave 进程从主服务器处获取二进制日志的内容并写入中继日志,然后由 IO 进程读取并执行中继日志中的语句。

中继日志的执行过程
在每个事务更新数据完成之前,master 在二进制日志记录这些改变。写入二进制日志完成后,master 通知存储引擎提交事务。
Slave 将 master 的 binary log 复制到其中继日志。首先 slave 开始一个工作线程(I/O),I/O 线程在 master 上打开一个普通的连接,然后开始 binlog dump process。binlog dump process 从 master 的二进制日志中读取事件,如果已经跟上 master,它会睡眠并等待 master 产生新的事件,I/O 线程将这些事件写入中继日志。
Sql slave thread(sql 从线程)处理该过程的最后一步,sql 线程从中继日志读取事件,并重放其中的事件而更新 slave 数据,使其与 master 中的数据一致,只要该线程与 I/O 线程保持一致,中继日志通常会位于 os 缓存中,所以中继日志的开销很小。
innodb事务日志包括redo log和undo log。redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。
需要注意的是undo log不是redo log的逆向过程,其实它们都算是用来恢复的日志:
1.redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。2.undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录
事物日志是innodb专用功能,这里只考虑innod存储引擎
出于性能和故障恢复的考虑,MySQL 服务器不会立即执行事务,而是先将事务记录在日志里面,这样可以将随机IO转换成顺序IO,从而提高IO性能。
事物日志默认在事物提交时,innodb是情况下会有两个文件,名称分别为ib_logfile0和ib_logfile1。当其中一个写满时,MySQL会将事务日志写入另一个日志文件(先清空原有内容)。当 MySQL 从崩溃中恢复时,会读取事务日志,将其中已经 commit 的事务写入数据库,没有 commit 的事务 rollback 。
redo log不是二进制日志。虽然二进制日志中也记录了innodb表的很多操作,也能实现重做的功能,但是它们之间有很大区别
这两种日志有以下三点不同。
redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
redo log的记录

write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
write pos 和 checkpoint 之间的是“粉板”上还空着的部分,可以用来记录新的操作。如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。
undo log有两个作用:提供回滚和多个行版本控制(MVCC)。
undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。
当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。有时候应用到行版本控制的时候,也是通过undo log来实现的:当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。
undo log默认存放在共享表空间中。

如果开启了 innodb_file_per_table ,将放在每个表的.ibd文件中。
在MySQL5.6中,undo的存放位置还可以通过变量 innodb_undo_directory 来自定义存放目录,默认值为"."表示data
当事务提交的时候,innodb不会立即删除undo log,因为后续还可能会用到undo log,如隔离级别为repeatable read时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。
但是在事务提交的时候,会将该事务对应的undo log放入到删除列表中,未来通过purge来删除。并且提交事务时,还会判断undo log分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的undo log页而浪费存储空间和性能。
通过undo log记录delete和update操作的结果发现:(insert操作无需分析,就是插入行而已)
delete操作实际上不会直接删除,而是将delete对象打上delete flag,标记为删除,最终的删除操作是purge线程完成的。
update分为两种情况:update的列是否是主键列。
如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进行的。如果是主键列,update分两部执行:先删除该行,再插入一行目标行。
原文作者:五分钟学SRE;如有侵权,请联系管理员删除。