本章将分析构成MySQL数据库和InnoDB存储引擎表的各种类型文件。 这些文件有以下这些:
1.参数文件 :告诉MySQL实例启动时在哪里可以找到数据库文件, 并且指定某些初始化参数, 这些参数定义了某种内存结构的大小等设置, 还会介绍各种参数的类型。
2.日志文件 :用来记录 MySQL实例对某种条件做出响应时写入的文件, 如错误日志文件、 二进制日志文件、 慢查询日志文件、 查询日志文件等。
3. socket文件: 当用UNIX域套接字方式进行连接时需要的文件。
4.pid文件: MySQL实例的进程ID文件。
5.MySQL表结构文件: 用来存放MySQL表结构定义文件。
6.存储引擎文件: 因为MySQL表存储引擎的关系, 每个存储引擎都会有自己的文件来保存各种数据。 这些存储引擎真正存储了记录和索引等数据。 本章主要介绍与lnnoDB有关的存储引擎文件。
3.1 参数文件
在第1章中已经介绍过了, 当MySQL实例启动时, 数据库会先去读一个配置参数文件, 用来寻找数据库的各种文件所在位置以及指定某些初始化参数, 这些参数通常定义了某种内存结构有多大等。 在默认情况下, MySQL实例会按照一定的顺序在指定的位 置进行读取, 用户只需通过命令mysql--help I grep my.cnf来寻找即可。
3.1.1 什么是参数
简单地说,可以把数据库参数看成一个键/值(key/value)对。第2章已经介绍了一个对于lnnoDB 存储引擎很重要的参数innodb_ buffer _pool_ size。如我们将这个参数设置为lG, 即innodb_ buffer _pool_ size= 1G 。这里的 “键” 是innodbb uffer _pool_size, "值” 是lG, 这就是键值对。
3.1.2 参数类型
MySQL数据库中的参数可以分为两类:
1.动态(dynamic)参数
2.静态(static)参数
动态参数意味着可以在MySQL实例运行中进行更改, 静态参数说明在整个实例生命周期内都不得进行更改, 就好像是只读(read only)的。 可以通过SET命令对动态的参数值进行修改, SET的语法如下:
这里可以看到global和session关键字, 它们表明该参数的修改是基于当前会话还是整个实例的生命周期。 有些动态参数只能在会话中进行修改, 如autocommit ; 而有些参数修改完后, 在整个实例生命周期中都会生效, 如binlog_cache_size; 而有些参数既可以在会话中又可以在整个实例的生命周期内生效。
3.2日志文件
日志文件记录了影响MySQL数据库的各种类型活动。 MySQL数据库 中常见的日志 文件有:
错误日志(errorlog)
二进制日志Cbinlog)
慢查询日志(slow query log)
查询日志(log)
3.2.1 错误日志
错误日志文件对MySQL的启动、 运行、 关闭过程进行了记录。 MySQLDBA在遇到问题时应该首先查看该文件以便定位问题。 该文件不仅记录了所有的错误信息, 也记录一些警告信息或正确的信息。 用户可以通过命令SHOW VARIABLES LIKE'log_error' 来定位该文件
3.2.2慢查询日志
3.2.1小节提到可以通过错误日志得到一些关于数据库优化的信息, 而慢查询日志(slow log)可帮助OBA定位可能存在问题的SQL语句,从而进行SQL语句层面的优化。例如, 可以在MySQL启动时设一个阔值,将运行时间超过该值的所有SQL语句都记录到慢查询日志文件中。OBA每天或每过一段时间对其进行检查, 确认是否有SQL语句需要进行优化。该阔值可以通过参数long_query_ time来设置,默认值为10, 代表 10秒。
在默认情况下,MySQL数据库并不启动慢查询日志, 用户需要手工将这个参数设为ON
这里有两点需要注意。首先,设置long_query_ time这个阔值后,MySQL数据库会记录运行时间超过该值的所有SQL语句,但运行时间正好等于long_query_ time的情况并不会被记录下。也就是说,在源代码中判断的是大于long_query_ time, 而非大于等于。其次,从MySQL5.1开始,long_query_ time开始以微秒记录SQL语句运行的时间,之前仅用秒为单位记录。 而这样可以更精确地记录SQL的运行时间, 供DBA分析。 对DBA来说, 条SQL语句运行 0.5秒和0.05秒是非常不同的, 前者可能已经进行 了表扫, 后面可能是进行了索引。
另一个和慢查询日志有关的参数是log_queries_ not_ using_ indexes, 如果运行的SQL,没有使用索引,同样会记录。
MySQL 5.6.5版本开始新增了一个参数log_ thr ottle_ queries_ not_ using_indexes, 用来表示每分钟允许记录到slowlog 的且未使用索引的SQL语句次数。 该值默认为 o. 表示没有限制。 在生产环境下, 若没有使用索引, 此类SQL语句会频繁地被记录到slow log, 从而导致slow log文件的大小不断增加, 故OBA可通过此参数进行配置。
DBA可以通过慢查询日志来找出有问题的SQL语句, 对其进行优化。 然而随着MySQL数据库服务器运行时间的增加, 可能会有越来越多的SQL查询被记录到了 慢查询日志文件中, 此时要分析该文件就显得不是那么简单和直观的 了。 而这时MySQL数据库提供的 mysqldumpslow命令,可以很好地帮助OBA解决该 问题。
3.2.3 查询日志
查询日志记录了所有对MySQL数据库请求的信息, 无论这些请求是否得到了正确的执行。 默认文件名为: 主机名.log。
3.2.4 二进制日志
二进制日志(binary log)记录了对MySQL数据库执行更改的所有操作, 但是不包括SELECT和SHOW这类操作, 因为这类操作对数据本身并没有修改。 然而, 若操作本身并没有导致数据库发生变化, 那么该操作可能也会写入二进制日志.
如果用户想记录SELECT和SHOW操作, 那只能使用查询日志, 而不是二进制日志。此外, 二进制日志还包括了执行数据库更改操作的时间等其他额外信息。 总的来说, 二进制日志主要有以下几种作用:
恢复(recovery): 某些数据的恢复需要二进制日志, 例如, 在一个数据库全备文件恢复后, 用户可以通过二进制日志进行point-in-time的恢复。
复制(replication) : 其原理与恢复类似, 通过复制和执行二进制日志使一台远程的MySQL数据库( 一般称为slave或standby)与一台MySQL数据库(一般称为master或primary)进行实时同步。
审计(audit) : 用户可以通过二进制日志中的信息来进行审计, 判断是否有对数据库进行注入的攻击。
通过配置参数log-bin[ =name]可以启动二进制日志。如果不指定name,则默认二进制日志文件名为主机名,后缀名为二进制日志的序列号,所在路径为数据库所在目录(datadir)。
二进制日志文件在默认情况下并没有启动,需要手动指定参数来启动。可能有人会质疑,开启这个选项是否会对数据库整体性能有所影响。不错,开启这个选项的确会影响性能,但是性能的损失十分有限。根据MySQL官方手册中的测试表明,开启二进制日志会使性能下降1%。但考虑到可以使用复制(replication)和point-in-time的恢复, 这些性能损失绝对是可以且应该被接受的。
以下配置文件的参数影响着二进制日志记录的信息和行为:
1.max_binlog_size
2.binlog_ cache_ size
3.sync_ binlog
4. binlog-do-db
5. binlog-ignore-db
6.log-slave-update
7.binlog_ format
参数 max_binlog_ size指定了单个二进制日志文件的最大值, 如果超过该值, 则产生新的二进制日志文件, 后缀名+1, 并记录到.index文件。 从MySQL5.0开始的默认值为I073 741 824, 代表1 G C在之前版本中 max_binlog_ size默认大小为 l.IG)。
当使用事务的表存储引擎(如InnoDB存储引擎)时, 所有未提交(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的状态, 可以判断当前binlog_ cache_ size的设置是否合适。 Binlog_ cache_ use记录了使用缓冲写二 进制日志的次数,binlog_cache_ disk_ use记录了使用临时文件写二进制日志的次数。
在默认情况下,二进制日志并不是在每次写的时候同步到磁盘(用户可以理解为缓冲写)。因此,当数据库所在操作系统发生右机时,可能会有最后一部分数据没有写入二进制日志文件中,这会给恢复和复制带来问题。参数sync_binlog= [NJ表示每写缓冲多少次就同步到磁盘。如果将N设为l, 即sync_binlog= l表示采用同步写磁盘的方式来写二进制日志,这时写操作不使用操作系统的缓冲来写二进制日志。sync_bin log的默认值为o, 如果使用InnoDB存储引擎进行复制,并且想得到最大的高可用性,建议将该值设为ON 。不过该值为ON 时,确实会对数据库的IO 系统带来一定的影响。
但是,即使将sync_bin log设为l, 还是会有一种情况导致问题的发生。当使用InnoDB存储引擎时,在一个事务发出COMMIT动作之前,由千sync_binlog为I, 因此会将二进制日志立即写入磁盘。如果这时已经写入了二进制日志,但是提交还没有发生,并且此时发生了宅机,那么在MySQL 数据库下次启动时,由于COMMIT 操作并没有发生,这个事务会被回滚掉。但是二进制日志已经记录了该事务信息,不能被回滚。这个问题可以通过将参数innodb_ support_xa设为1来解决,虽然innodb_support_ xa与XA事务有关,但它同时也确保了二进制日志和InnoDB存储引擎数据文件的同步。
参数binlog-do-db 和binlog-ignore-db表示需要写入或忽略写入哪些库的日志。默认为空,表示需要同步所有库的日志到二进制日志。
如果当前数据库是复制中的slave角色,则它不会将从master取得并执行的二进制日志写入自己的二进制日志文件中去。如果需要写入,要设览log-slave-update 。如果需要搭建master=>slave=>slave架构的复制,则必须设置该参数。
binlog_ format参数十分重要,它影响了记录二进制日志的格式。在MySQL 5.1版本之前,没有这个参数。所有二进制文件的格式都是基于SQL语句(statement)级别的,因此基于这个格式的二进制日志文件的复制(Replication)和Oracle的逻辑Standby 有点相似。同时, 对于复制是有一定要求的。如在主服务器运行rand、uuid等函数,又或者使用触发器等操作,这些都可能会导致主从服务器上表中数据的不一致(not sync)。另一个影响是, 会发现lnnoDB存储引擎的默认事务隔离级别是REPEATABLE READ 。这其实也是因为二进制日志文件格式的关系,如果使用READ COMMITTED的事务隔离级别(大多数数据库,如Oracle, Microsoft SQL Server 数据库的默认隔离级别),会出现类似丢失更新的现象, 从而出现主从数据库上的数据不一致。
MySQL 5.1开始引入了binlog_format参数, 该参数可设的值有STATEMENT、ROW和MIXED。
(I) STATEMENT格式和之前的MySQL版本一样,二进制日志文件记录的是日志的逻辑SQL语句。
(2)在ROW格式下, 二进制日志记录的不再是简单的SQL语句了, 而是记录表的行更改情况。基于ROW格式的复制类似于Or acle 的物理Standby (当然, 还是有些区别)。同时, 对上述提及的Statement格式下复制的问题予以解决。从MySQL 5.1版本开始, 如果设置了binlog_ format为ROW , 可以将InnoDB的事务隔离基本设为READCOMMITTED, 以获得更好的并发性。
(3)在MIXED格式下, MySQL默认采用STATEMENT格式进行二进制日志文件的记录, 但是在一些情况下会使用ROW格式, 可能的情况有:
1) 表的存储引擎为NOB,这时对表的DML操作都会以ROW格式记录。
2)使用了UUIDO、USERO、C URRENT_USERQ、FOUND_ROWSQ、ROW_COUNTQ等不确定函数。
3)使用了INSERT DELAY语句。
4)使用了用户定义函数(UDF)。
5)使用了临时表(t empor ary table) 。
此外, binlog_format参数还有对于存储引擎的限制, 如表3-1所示。
3.3 套接字文件
前面提到过,在UNIX系统下本地连接MySQL可以采用UNIX域套接字方式,这种方式需要一个套接字(socket)文件。套接字文件可由参数socket控制。一般在/tmp目录下,名为mysql.sock。
3.4 pid文件
当MySQL实例启动时,会将自己的进程ID写人一个文件中一—该文件即为pid文件。该文件可由参数pid_file控制,默认位于数据库目录下,文件名为主机名.pid。
3.5 表结构定义文件
因为MySQL插件式存储引擎的体系结构的关系, MySQL数据的存储是根据表进行的, 每个表都会有与之对应的文件。 但不论表采用何种存储引擎, MySQL都有一个以frm为后缀名的文件, 这个文件记录了该表的表结构定义。
frm还用来存放视图的定义, 如用户创建了一个v_a视图, 那么对应地会产生一 个v_a.frm文件, 用来记录视图的定义, 该文件是文本文件, 可以直接使用cat命令进行查看
3.6 InnoDB存储引擎文件
之前介绍的文件都是MySQL数据库本身的文件, 和存储引擎无关。 除了这些文件外, 每个表存储引擎还有其自己独有的文件。 本节将具体介绍与InnoDB存储引擎密切相关的文件, 这些文件包括重做日志文件、 表空间文件。
3.6.1 表空间文件
lnnoDB采用将存储的数据按表空间(tablespace)进行存放的设计。 在默认配置下会有 一个初始大小为10MB, 名为ibdatal的文件 。 该文件就是默认的表空间文件 (tablespace file), 用户可以通过参数ionodb_data_ file _path对其进行设置, 格式如下:
innodb_data_file_path=data/ile_specl [; datafile_spec2] ...
用户可以通过多个文件组成一个表空间, 同时制定文件的 属性, 如:
[mysqld)
innodb_data_file_path = /db/ibdatal: 2000M; /dr2/db/ ibdata2: 2000M: autoextend
这里将/db/ibdata l和/dr2/db/ibdata2 两个文件用来组成表空间。若这两个文件位于不同的磁盘上, 磁盘的负载可能被平均, 因此可以提高数据库的整体性能。 同时, 两个 文件的文件名后都跟了属性, 表示文件 idbdatal的大小为2000MB, 文件 ibdata2的大小为2000MB, 如果用完了这2000MB, 该文件可以自动增长(autoextend)。
设置innodb_data_ file _path参数后, 所有基于InnoDB存储引擎 的表的数据都会记录到该共享表空间中。 若设置了参数innodb_ file _per_ table , 则用户可以将每个基于 InnoDB存储引擎的表产生一个独立表空间。 独立表空间的命名规则为: 表名.ibd。通过这样的方式, 用户不用将所有数据都存放于默认的表空间中。
3.6.2 重做日志文件
在默认情况下,在InnoDB存储引擎的数据目录下会有两个名为ib_ logfileO和ib_ logfilel的文件。在MySQL官方手册中将其称为InnoDB存储引擎的日志文件,不过更准确的定义应该是重做日志文件(redolog file)。为什么强调是重做日志文件呢?因为 重做日志文件对于InnoDB存储引擎至关重要,它们记录了对于InnoDB存储引擎的事务日志。
当实例或介质失败 (media failure) 时, 重做日志文件就能派上用场。 例如, 数据库 由于所在主机掉电导致实例失败, InnoDB 存储引擎会使用重做日志恢复到掉电前的时刻, 以此来保证数据的完整性。
每个 InnoDB 存储引擎至少有 1 个重做日志文件组 (group), 每个文件组下至少有 2 个重做日志文件, 如默认的 ib_ logfileO和 ib_ logfile 1。为了得到更高的可靠性, 用户 可以设置多个的镜像日志组 (mirrored log groups), 将不同的文件组放在不同的磁盘上, 以此提高重做日志的高可用性。 在日志组中每个重做日志文件的大小一致, 并以循环写人的方式运行。InnoDB存储引擎先写重做日志文件I,当达到文件的最后时,会切换至重做日志文件2, 再当重做日志文件2也被写满时,会再切换到重做日志文件1中。
下列参数影响着重做日志文件的属性:
innodb_log_file_size
l innodb _log_ files_ in _group
l innodb _mirrored_ log_groups
l innodb _ log_group _home_ dir
参数 innodb_log_file_size 指定每个重做日志文件的大小。在 lnnoDB1.2.x 版本之前, 重做日志文件总的大小不得大于等于 4GB, 而 1.2.x 版本将该限制扩大为了 512GB。
参数 innodb_log_files _in _group 指定了日志文件组中重做日志文件的数景,默认为2。参数 innodb_ mirrored _log_groups 指定了日志镜像文件组的数量,默认为1, 表示只有一个日志文件组,没有镜像。若磁盘本身已经做了高可用的方案,如磁盘阵列,那么可以不开启重做日志镜像的功能。最后,参数innodb_log_group _home_ dir 指定了日志文件组所在路径,默认为.I'表示在 MySQL 数据库的数据目录下。
重做日志文件的大小设置对于 InnoDB 存储引擎的性能有着非常大的影响。一方面做日志文件不能设姓得太大,如果设置得很大,在恢复时可能需要很的时间;一方面又不能设置得太小了, 否则可能导致一个事务的日志需要多次切换重做日志文件。此外, 重做日志文件太小会导致频繁地发生async checkpoint, 导致性能的抖动。
在InnoDB存储引擎中,对于各种不同的操作有着不同的重做日志格式。到InnoDB1.2.X版本为止,总共定义51种重做日志类型。 虽然各种重做日志的类型不同, 但是它们有着基本的格式, 表3-2显示了重做日志条目的结构:
从表3-2可以看到重做日志条目是由4个部分组成:
1 redo_log_type占用1字节, 表示重做日志的类型
redo_log_body
2 space表示表空间的ID, 但采用压缩的方式, 因此占用的空间可能小于4字节
3 page_no表示页的偏移盈, 同样采用压缩的方式
4 redo_log_body表示每个重做日志的数据部分, 恢复时需要调用相应的函数进行解析
在第2章中已经提到, 写入重做日志文件的操作不是直接写, 而是先写入一个重做日志缓冲(redo log buff er)中, 然后按照一定的条件顺序地写入日志文件。图3-3很好地诠释了重做日志的写入过程。
从重做日志缓冲往磁盘写人时, 是按512个字节, 也就是一个扇区的大小进行写入。因为扇区是写入的最小单位, 因此可以保证写入必定是成功的。因此在重做日志的写人过程中不需要有doublewrite。
前面提到了从日志缓冲写入磁盘上的重做日志文件是按一定条件进行的, 那这些条件有哪些呢?第2章分析了主线程(master thread), 知道在主线程中每秒会将重做日志缓冲写人磁盘的重做日志文件中, 不论事务是否已经提交。另一个触发写磁盘的过程是由参数innodb_fl ush_ log_ at_ trx_ com mit控制, 表示在提交(commit)操作时, 处理重做日志的方式。
参数innodb_flush_ log_ at_ trx_ commit的有效值有0、1、2。0代表当提没患缢啪 不将事务的重做日志写入磁盘上的日志文件,而是等待主线程每秒的刷新。1和2不同的地方在于:1表示在执行commit时将重做日志缓冲同步写到磁盘,即伴有fsync的调用。2表示将重做日志异步写到磁盘,即写到文件系统的缓存中。因此不能完全保证在执行commit时肯定会写入重做日志文件,只是有这个动作发生。
因此为了保证事务的ACID中的持久性,必须将innodb_flush_log_at_trx_commit设置为1,也就是每当有事务提交时,就必须确保事务都已经写入重做日志文件。那么当数据库因为意外发生宅机时,可以通过重做日志文件恢复,并保证可以恢复已经提交的事务。而将重做日志文件设置为0或2,都有可能发生恢复时部分事务的丢失。不同之处在于,设置为2时,当MySQL数据库发生右机而操作系统及服务器并没有发生者机时,由于此时未写人磁盘的事务日志保存在文件系统缓存中,当恢复时同样能保证数据 不丢失。
3.7 小结
本章介绍了与MySQL数据库相关的一些文件,并了解了文件可以分为MySQL数据库文件以及与各存储引擎相关的文件。与MySQL数据库有关的文件中,错误文件和 二进制日志文件非常重要。当MySQL数据库发生任何错误时,OBA首先就应该去查看错误文件,从文件提示的内容中找出问题的所在。当然,错误文件不仅记录了错误的内容,也记录了警告的信息,通过一些警告也有助于 OBA对于数据库和存储引擎进行优化。
二进制日志的作用非常关键,可以用来进 行point in time的恢复以及复制(replication)环境的搭建。因此,建议在任何时候时都启用二进制日志的记录。 从MySQL 5.1开始,二进制日志支持STATEMENT、ROW、MIX三种格式,这样可以更好地保证从数据库与主数据库之间数据的一致性。当然 OBA应该十分清楚这三种不同 格式之间的差异。
本章的最后介绍了和InnoDB存储引擎相关的文件,包括表空间文件和重做日志文件。表空间文件是用来管理InnoDB存储引擎的存储,分为共享表空间和独立表空间。重做日志非常的重要,用来记录InnoDB存储引擎的事务日志,也因为重做日志的存在,才使得InnoDB存储引擎可以提供可靠的事务。