MySQL常见的日志文件有:
1.错误日志 - MySQL的启动,运行、关闭过程等
2.慢查询日志 - 运行时间超过某个阀值的sql或者运行sql语句没有使用索引
3.查询日志 - 记录所有对MySQL数据库请求的信息
4.二进制日志 - 记录对数据库执行更改的所有操作,常用于恢复,复制,审计
这些日志影响着MySQL数据库的各种类型活动,可以帮助DBA对MySQL数据库的运行状态进行诊断,从而更好的进行数据库层次的优化。
一、 错误日志
错误日志文件是对MySQL的启动、运行、关闭过程进行了记录。该文件不仅记录了所有的错误信息,也记录了一些警告信息或正确的信息。可以通过 show variables like 'log_error'; 来定位该文件位置。
mysql> show variables like 'log_error'; |
可以看到错误文件的路径和文件名,在默认情况下错误文件的文件名为服务器的主机名(Lenove-PC主机名),所以错误文件名为Lenovo-PC.err。当出现MySQL数据库不能正常启动时,第一个必须查找的文件应该就是错误日志文件,该文件记录了错误信息,能很好的指导用户发现问题。当数据库不能重启时,通过查找错误日志判断原因,一些警告(warning)日志很友好地说明了问题所在。
场景:(缺少实例)
1.找不到权限库mysql
2.告诉用户需要增大InnoDB存储引擎的redo log
二、慢查询
慢查询日志(slow log)可以定位可能存在问题的SQL语句,从而进行SQL语句层次的优化。
例如:可以在MySQL启动时设一个阀值,将运行时间超过该值的所有SQL语句都记录到慢查询日志文件中。该阀值可以通脱参数long_query_time来设置,默认值为10,代表10秒(默认情况下,MySQL数据库并不启动慢查询日志,需要手动开启)
慢日志查询没有开启,可以开启一下。 set global slow_query_log = 'on'; 找到my.cnf,添加如下内容
重启mysql。
|
这里需要注意的有两点:首先,设置long_query_time这个阀值后,MySQL数据库会记录运行时间超过该值的所有SQL语句,但运行时间正好等于long_query_time的情况并不会被记录下,也就是说在源码中判断的是大于long_query_time,而非大于等于。其次,从MySQL 5.1 开始,long_query_time开始以微妙记录SQL语句运行的时间。之前仅用秒为单位记录,而这样可以更精确的记录SQL的运行时间,供DBA分析,对DBA来说,一条sql运行0.5秒和0.05秒是非常不同的。前者可能进行了表扫,后面可能进行了索引。
另一个和慢查询日志相关的参数是log_queries_not_using_indexes,如果运行的SQL语句没有使用索引,则MySQL数据库同样会将这条SQL语句记录到慢查询日志文件。首先确认打开了log_queries_not_using_indexes;
MySQL 5.6.5 开始新增了一个参数log_throttle_queries_not_using_indexes,用来表示每分钟允许记录到slow log 的且未使用索引的SQL语句次数,该值默认为0,表示没有限制,在生产环境下,若没有使用索引,此类SQL语句会频繁地被记录到slow log ,从而导致slow log 文件的大小不断增加。
slow log 文件越来越大可以使用MySQL数据库提供的mysqldumpslow命令
得到执行时间最长的10条SQL语句
mysqldumpslow -s al -n 10 xxx.log
在MySQL 5.1 开始将慢查询的日志记录放入一张表中,这使得用户的查询更加方便和直观,慢查询表在mysql架构中,名为slow_log,
show create table mysql.slow_log; CREATE TABLE `slow_log` ( |
参数指定了log_output指定了慢查询输出的格式,默认为FILE,可以将它设为TABLE然后就可以查询mysql架构的slow_log表了,
mysql> show variables like 'log_output +---------------------+------------------------------------+------------+-----------+-----------+---------------+----+----------------+-----------+-----------+------------------+ |
参数log_output是动态的,并且是全局的,因此用户可以在线进行修改,查看slow_log表的定义会发现该表使用的是CSV引擎,对大数据下的查询效率可能不高。用户可以把slow_log表的引擎转换成MyISAM,并在start_time列上添加索引以进一步提高查询的效率。但是如果已经启动了慢查询,将会提示报错。
mysql> alter table mysql.slow_log engine=MyISAM; 1580 - You cannot 'ALTER' a log table if logging is enabled mysql> set global slow_query_log=off; Query OK, 0 rows affected mysql> alter table mysql.slow_log engine=MyISAM; Query OK, 1 row affected Records: 1 Duplicates: 0 Warnings: 0 mysql> set global slow_query_log=on ; Query OK, 0 rows affected mysql> |
虽然讲slow_log表的存储引擎更改成MyISAM后,还是会对数据库造成额外的开销,但是很多关于慢查询的参数都是动态的,用户可以方便的在线进行设置或者修改。
MySQL的slow_log 通过运行时间来对SQL语句进行捕获,这是一个非常有用的优化技巧,但是当数据库的容量较小时,可能因为数据库刚建立,此时非常大的可能是数据全部被缓存在缓冲池中,SQL语句运行的时间可能都非常短,一般都是0.5秒。
InnoSQL版本加强了对SQL语句的捕获方式,在原版MySQL的基础上在slow_log中增加了对于逻辑读取(logical reads)和物理读取(physical reads)的统计。物理/逻辑读取区别
对于查询处理,可将其分为逻辑查询处理和物理查询处理。逻辑查询处理表示执行查询应该产生什么样的结果,而物理查询代表MySQL数据库是如何得到结果的。 逻辑查询处理 MySQL真正的执行顺序如下: (8)SELECT (9)DISTINCT<select_list> (1)FROM <left_table> (3)<join_type>JOIN<right_table> (2) ON <join_condition> (4)WHERE <where_condition> (5)GROUP BY <group_by_list> (6)WITH {CUBE|ROLLUP} (7)HAVING<having_condition> (10)ORDER BY<order_by_list> (11)LIMIT <limit_number> FORM:对FORM子句中的左表< left_table > 和右表 < right_table >执行笛卡儿积,产生虚拟表VT1。 ON:对虚拟表VT1应用ON筛选,只有那些符合< join_condition >的行才被插入到虚拟表VT2中。 JOIN:如果指定了OUTER JOIN,那么保留表中未匹配的行作为外部行添加到虚拟表VT2中,产生虚拟表VT3。如果FROM字句包含两个以上表,则对上一个连接生成的结果表VT3和下一个表重复执行步骤1~步骤3,直到处理完所有的表为止。 WHERE:对虚拟表VT3应用WHERE过滤条件,只有符合< where_condition >的记录才被插入到虚拟表VT4中。 GROUP BY:根据GROUP BY子句中的列,对VT4中的记录进行分组操作,产生虚拟表VT5. CUBE|ROLLUP:对虚拟表VT5进行 CUBE或ROLLUP,产生VT6. HAVING:对虚拟表VT6应用HAVING过滤器,只有符合< having_condition >的记录才能被插入虚拟表VT7. SELECT:第二次执行SELECT操作,选择指定的咧,插入到虚拟表VT8。 DISTINCT:去除重复数据,产生虚拟表VT9。 ORDER BY:将虚拟表VT9中的记录按照< order_by_list >进行排序操作,产生虚拟表VT10。 LIMIT:取出指定行的记录,产生虚拟表VT11,并返回给查询用户。 物理查询处理 上面是逻辑查询处理,但是数据库也许并不会按照逻辑查询处理的方式进行查询。MySQL数据库层有Parser和Optimizer两个组件。Parser的工作就是分析SQL语句,而Optimizer的工作就是对这个SQL语句进行优化,选择一条最优的路径来选取数据,但是必须保证物理查询处理的最终结果和逻辑查询处理的结果是相等的。 如果表上建有索引,那么优化器就会判断SQL语句是否可以利用该索引来进行优化。如果没有可以利用的索引,可能整个SQL语句的执行代价非常大。 假设表A和表B都是有10万行数据,并且两个表都没有索引,因此最终SQL解析器解析的执行结果为逻辑处理的步骤,共经过11个步骤来进行数据的查询。最终根据笛卡尔积生成一张虚表VT1,共100亿行数据,执行这条SQL语句一般的电脑至少得跑一个多小时。 然而,如果这时候表B上添加一个主键值,在执行这条SQL语句,那么只需话费1秒。促使这个查询时间大幅减少的原因就是添加索引后避免了笛卡儿积表的产生。 物理查询会根据索引来进行优化。 |
用户可以通过额外的参数long_query_io将超过指定逻辑IO次数的SQL语句记录到slow log中。该值默认为100.即表示对于逻辑读取次数大于100的SQL语句,记录到slow log中,而为了兼容原MySQL数据库的运行方式,还添加了参数slow_query_type,来表示启动slow log 的方式,可选值为:
0 表示不将SQL语句记录到slow log
1 表示根据运行时间将SQL语句记录到slow log
2表示根据逻辑IO次数将SQL语句记录到slow log
3表示根据运行时间及逻辑IO次数将SQL语句记录到slow log
三、查询日志
查询日志记录了所有对MySQL数据库请求的信息,无论这些请求是否得到正确的执行,默认文件名为:主机名.log
mysql> show variables like 'general%'; +------------------+----------------------------------------------------------+ | Variable_name | Value | +------------------+----------------------------------------------------------+ | general_log | OFF | | general_log_file | C:ProgramDataMySQLMySQL Server 5.5DataLenovo-PC.log | +------------------+----------------------------------------------------------+ 2 rows in set mysql> set global general_log=on; Query OK, 0 rows affected mysql> show variables like 'general%'; +------------------+----------------------------------------------------------+ | Variable_name | Value | +------------------+----------------------------------------------------------+ | general_log | ON | | general_log_file | C:ProgramDataMySQLMySQL Server 5.5DataLenovo-PC.log | +------------------+----------------------------------------------------------+ 2 rows in set mysql> |
查询日志甚至记录了对Access denied(拒绝访问)的请求,即对于未能正确执行的SQL语句,查询日志也会进行记录,同样的,从MySQL 5.1 开始,可以将查询日志的记录放入mysql架构下general_log表中,该表的使用方法和slow_log基本一样。
四、二进制日志
二进制日志(binary log)记录了对MySQL数据库执行更改的所有操作,但是不包括select和show这类操作,因为这类操作对数据本身并没有修改。然而,若操作本身并没有导致数据库发送变化,那么该操作可能也会写入二进制文件。
在mysqld配置项下面加上log_bin=mysql_bin [mysqld]
log_bin = mysql_bin
mysql> show variables like 'log_bin'; |
如上,从返回结果changed为0,这意味着该操作并没有导致数据库的变化,但是在二进制日志中的确进行了记录。
如果用户想记录select和show操作,那只能使用查询日志,而不是二进制日志。此外,二进制日志还包括了执行数据库更改操作的时间等其他额外信息,总的来说,二进制日志主要有以下几种作用:
1.恢复(recovery):某些数据的恢复需要二进制日志,例如,在一个数据库全备文件恢复后,用户可以通过二进制日志进行point-in-time的恢复
2.复制(replication):其原理与恢复类似,通过复制和执行二进制日志使一台远程的MySQL(slave)数据库与另一台MySQL(master)数据库进行实时同步。
3.审计(audit):用户可以通过二进制日志中的信息来进行审计,判断是否有对数据库进行注入的攻击
通过配置log_bing[=name] 可以启动二进制日志,如果不指定name,则默认二进制日志文件名为主机名,后缀名为二进制日志的序列号,所在路径为数据库所在目录datadir
这里的mysql_bin.00001即为二进制日志文件,mysql_bin.index为二进制的索引文件,用来存储过往产生的二进制日志序号,在通常情况下,不建议手工修改这个文件
二进制日志文件在默认情况下并没有启动,需要手动指定参数来启动,开启这个选项虽然会对数据库整体性能有所影响,但是,性的损失十分有限,性能下降1%,但考虑到可以使用复制(relication)和point-in-time的恢复,这些性能损失绝对是可以且应该被接受的。
以下配置文件的参数影响着二进制日志记录的信息和行为。
max_binlog_size 指定了单个二进制日志文件的最大值,如果超过该值,则产生心得二进制文件,后缀+1,并记录到.index文件。
binlog_cache_size 事务期间使用的缓冲
sync_binlog 表示每写缓冲多少次就同步磁盘
binlog-do-db 表示需要写入那些库的日志,默认为空,表示需要同步所有库的日志到二进制日志
binlog-ignore-db 表示需要忽略那些库的日志,默认为空
log-slave-update 将从master获取并执行的二进制日志写入自己的二进制日志文件中
binlog_format 记录了二进制日志的格式
当使用事务的表存储引擎时,所有未提交(uncommitted)的二进制日志会被记录到一个缓存中去,等该事务提交(committed)时直接将缓冲中的二进制日志写入二进制日志文件,而该缓冲的大小由binlog_cache_size决定,默认大小为32k,此外,binlog_cache_size是基于会话(session)的,也就是说,当一个线程开始一个事务时,MySQL会自动分配一个大小为binlog_cache_size的缓存,因此该值的设置需要相当小心,不能设置过大。当一个事务的记录大于设定的binlog_cache_size时,MySQL会把缓冲中的日志写入一个临时文件中,因此该值又不能设置太小。通过show global status 命令查看binlog_cache_use,binlog_cache_disk_use的状态,可以判断当前biglog_cache_size的设置是否合适。Binlog_cache_use记录了使用缓冲写二进制日志的次数,biglog_cache_disk_use记录了使用临时文件写二进制日志的次数。
mysql> show global status like 'binlog_cache%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | Binlog_cache_disk_use | 0 | | Binlog_cache_use | 32768 | +-----------------------+-------+ 2 rows in set mysql> |
使用缓冲次数为32768 ,临时文件使用次数为0,看来32k的缓冲大小对于当前这个MySQL数据库完全够用,暂时没有必要增加biglog_cache_size的值。
在默认情况下,二进制日志并不是在每次写的时候同步到磁盘的(可以理解为缓冲写)。因此,当数据库所在操作系统发生宕机时,可能会有最后一部分数据没有写入二进制日志文件中,这会给恢复和复制带来问题。参数sync_binlog=[N]表示每写缓冲多少次就同步到磁盘,如果将N设为1,即sync_biglog=1表示采用同步写磁盘的方式来写二进制日志,这时写操作不使用操作系统的缓冲来写二进制日志。sync_biglog的默认值为0,如果使用InnoDB存储引擎进行复制,并且想得到最大的高可用性,建议将该值设置为ON,不过该值为ON时,确实会对数据库的IO系统带来一定的影响。
但是,即使将sync_binlog设为1,还是会有一种情况导致问题的发生。当使用InnoDB存储引擎时,在一个事务发出COMMIT动作之前,由于sync_binlog为1,因此会将二进制日志立即写入磁盘,如果这时已经写入可二进制日志,但是提交还没有发生,并且此时发生宕机,那么在MySQL数据库下次启动时,由于COMMIT操作并没有发生,这个事务会被回滚掉。但是二进制日志已经记录了该事物信息,不能被回滚。这个问题可以通过将参数innode_support_xa设为1来解决,虽然innodb_support_xa与XA事务有关,但它同时也保证了二进制日志和InnoDB存储引擎数据文件的同步。
binlog_format参数影响了二进制文件的格式:
STATEMENT格式和之前MySQL版本一样,二进制日志文件记录的是日志的逻辑SQL语句
在ROW格式下,二进制日志记录的不再是简单的SQL语句,而是记录表的行更改情况,基于ROW格式的复制类似于Oracle的物理Standby。
在MIXED格式下,MySQL默认采用STATEMENT格式进行二进制日志文件的记录,但是在一些情况下,会使用ROW格式,可能的情况有:
表的存储引擎为NDB,这时对表的DML操作都会以ROW格式记录
使用UUID(),USER(),CURRENT_USER(),FOUND_ROWS(),ROW_COUNT()等不确定函数
使用了INSERT DELAY语句
使用了用户定义函数
使用了临时表