MySQL的存储引擎
查看Mysql支持的所有引擎命令 show engines
从上图可见,MySQL 当前默认的存储引擎是 InnoDB。并且,所有的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。
MyISAM 和 InnoDB 有什么区别?
MySQL 5.5 之前,MyISAM 引擎是 MySQL 的默认存储引擎,虽然,MyISAM 的性能还行,各种特性也还不错(比如全文索引、压缩、空间函数等)。但是,MyISAM 不支持事务和行级锁,而且最大的缺陷就是崩溃后无法安全恢复。MySQL 5.5 版本之后,InnoDB 是 MySQL 的默认存储引擎。
1.是否支持行级锁
MyISAM 只有表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。
2.是否支持事务
MyISAM 不提供事务支持。
InnoDB 提供事务支持,实现了 SQL 标准定义了四个隔离级别,具有提交(commit)和回滚(rollback)事务的能力。并且,InnoDB 默认使用的 REPEATABLE-READ(可重读)隔离级别是可以解决幻读问题发生的(基于 MVCC 和 Next-Key Lock)。
3.是否支持外键
MyISAM 不支持,而 InnoDB 支持。
4.是否支持数据库异常崩溃后的安全恢复
MyISAM 不支持,而 InnoDB 支持。
使用 InnoDB 的数据库在异常崩溃后,数据库重新启动的时候会保证数据库恢复到崩溃前的状态。这个恢复的过程依赖于 redo log
MySQL日志
MySQL 中常见的日志有哪些?
MySQL 中常见的日志类型主要有下面几类(InnoDB 存储引擎):
错误日志(error log) :对 MySQL 的启动、运行、关闭过程进行了记录。
二进制日志(binary log) :主要记录的是更改数据库数据的 SQL 语句。
事务日志(redo log 和 undo log) :redo log 是重做日志,undo log 是回滚日志。
一般查询日志(general query log) :已建立连接的客户端发送给 MySQL 服务器的所有 SQL 记录,因为 SQL 的量比较大,默认是不开启的,也不建议开启。
慢查询日志(slow query log) :执行时间超过 long_query_time秒钟的查询,解决 SQL 慢查询问题的时候会用到。
中继日志(relay log) :relay log 是复制过程中产生的日志,很多方面都跟 binary log 差不多。不过,relay log 针对的是主从复制中的从库。
DDL 日志(metadata log) :DDL 语句执行的元数据操作。
binog 主要记录了什么?
MySQL binlog(binary log 即二进制日志文件) 主要记录了 MySQL 数据库中数据的所有变化(数据库执行 的所有 DDL 和 DML 语句)。
binlog 有一个比较常见的应用场景就是主从复制,MySQL 主从复制依赖于 binlog 。另外,常见的一些同步 MySQL 数据到其他数据源的工具(比如 canal)的底层一般也是依赖 binlog 。
binlog 通过追加的方式进行写入,大小没有限制。并且,我们可以通过max_binlog_size参数设置每个binlog 文件的最大容量,当文件大小达到给定值之后,会生成新的 binlog 文件来保存日志,不会出现前面写的日志被覆盖的情况
binlog日志的记录格式
三种记录格式** statement,row,mixed**
指定statement,记录的内容是SQL语句原文,比如执行一条update T set update_time=now() where id=1,同步数据时,会执行记录的SQL语句,但是有个问题,update_time=now()这里会获取当前系统时间,直接执行会导致与原库的数据不一致。
指定为row,记录的内容不再是简单的SQL语句了,还包含操作的具体数据
mixed,记录的内容是前两者的混合
MySQL会判断这条SQL语句是否可能引起数据不一致,如果是,就用row格式,否则就用statement格式。
redo log 如何保证事务的持久性?
InnoDB 存储引擎是以页为单位来管理存储空间的,我们往 MySQL 插入的数据最终都是存在于页中的,准确点来说是数据页这种类型。为了减少磁盘 IO 开销,还有一个叫做 Buffer Pool(缓冲池)的区域,存在于内存中。当我们的数据对应的页不存在于 Buffer Pool 中的话, MySQL 会先将磁盘上的页缓存到 Buffer Pool 中,这样后面我们直接操作的就是 Buffer Pool 中的页,这样大大提高了读写性能。
一个事务提交之后,我们对 Buffer Pool 中对应的页的修改可能还未持久化到磁盘。这个时候,如果MySQL 突然宕机的话,这个事务的更改是不是直接就消失了呢?很显然是不会的,如果是这样的话就明显违反了事务的持久性。
MySQL InnoDB 引擎使用 redo log 来保证事务的持久性。redo log 主要做的事情就是记录页的修改,比如某个页面某个偏移量处修改了几个字节的值以及具体被修改的内容是什么。redo log 中的每一条记录包含了表空间号、数据页号、偏移量、具体修改的数据,甚至还可能会记录修改数据的长度(取决于redo log 类型)。
在事务提交时,我们会将 redo log 按照刷盘策略刷到磁盘上去,这样即使 MySQL 宕机了,重启之后也能恢复未能写入磁盘的数据,从而保证事务的持久性。也就是说,redo log 让 MySQL 具备了崩溃回复能力。
不过,我们也要注意设置正确的刷盘策略 innodb_flush_log_at_trx_commit ,根据 MySQL 配置的刷盘策略的不同,MySQL 宕机之后可能会存在轻微的数据丢失问题。
刷盘策略 innodb_flush_log_at_trx_commit 的默认值为 1,设置为 1 的时候才不会丢失任何数据。为了保证事务的持久性,我们必须将其设置为 1
binlog 和 redolog 有什么区别?
- binlog 主要用于数据库还原,属于数据级别的数据恢复,主从复制是 binlog 最常见的一个应用场景。redolog 主要用于保证事务的持久性,属于事务级别的数据恢复。
- redolog 属于 InnoDB 引擎特有的,binlog 属于所有存储引擎共有的,因为 binlog 是 MySQL 的Server 层实现的。
- redolog 属于物理日志,主要记录的是某个页的修改。binlog 属于逻辑日志,主要记录的是数据库执行的所有 DDL 和 DML 语句。
- binlog 通过追加的方式进行写入,大小没有限制。redo log 采用循环写的方式进行写入,大小固定,当写到结尾时,会回到开头循环写日志。
在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机不一样。
undo log 如何保证事务的原子性?
每一个事务对数据的修改都会被记录到 undo log ,当执行事务过程中出现错误或者需要执行回滚操作的话,MySQL 可以利用 undo log 将数据恢复到事务开始之前的状态。
undo log 属于逻辑日志,记录的是 SQL 语句,比如说事务执行一条 DELETE 语句,那 undo log 就会记录一条相对应的 INSERT 语句。
MySQL InnoDB 引擎使用 redo log(重做日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性。