MySQL进阶二(InnoDB存储引擎)

大纲

  1. 存储引擎介绍
  2. MySQL架构与内部模块
  3. innoDB的磁盘结构与内存结构

继续上一篇,我们在得到执行计划之后,sql是不是就可以执行了?这里有两个问题:
1.数据存放在哪里?或者说放在一个什么结构里面
2.执行计划在哪里执行,怎么执行?

1.存储引擎的基本介绍

我们先来看第一个问题,在关系型数据库中,数据是存放在表中,我们可以把这个表理解成Excel里面的表格,所以我们在存储数据时还要组织数据的存储结构,这个存储结构就是由我们的存储引擎决定的,在MySQL里面,支持多种存储引擎,存储引擎是以插件的形式存在,那么这些存储引擎的差别在哪里呢?

1.1存储引擎比较

常见的存储引擎
  innoDB和MyISAM是我们用的最多的两个存储引擎,在MySQL5.5之前,默认的存储引擎是MyISAM,它是MySQL自带的。
  MyISAM前身是ISAM(Indexed Sequential Access Method:利用索引,顺序存取数据的方法)。
  MySQL5.5之后默认的存储引擎改成了innoDB,主要是因为InnoDB支持事务,支持行级锁,对于业务一致性的要求高的场景来说更合适。


如果需要一个用于查询的临时表,可以用memory,顾名思义就是存在于内存中的表,访问速度会很快。
具体各个存储引擎的特性:https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html

1.2.执行引擎

第二个问题,执行计划就是由执行引擎去操作存储引擎的,不同的存储引擎实现了相同的API,因此对于执行引擎来说,不同的存储引擎的操作是一样的。

2.MySQL体系架构总结
2.1模块详解

Connectors:用来支持各种语言和SQL的交互,比如PHP,Java等。
management Service&utililties:系统管理和控制工具,包括备份恢复,MySQL复制,集群等。
connection pool:连接池,管理需要缓冲的资源,包括用户密码权限线程等。
sql interface:用来接收客户端的sql命令,并返回结果。
parser:用来解析sql语句。
optimizer:查询优化器。
cache & buffers:查询缓存,还有表缓存,key缓存,权限缓存等。
pluggable storage engines:插件式存储引擎,提供api给服务层使用。

2.2架构分层
3.一条更新SQL是如何执行的?

基本流程和查询SQL是一致的,解析器-》优化器-》执行引擎,主要的区别在于拿到符合条件的数据之后的操作。

3.1缓冲池 Buffer Pool

  首先,innoDB的数据都是存储在磁盘中的,innoDB操作数据有一个最小单元,叫做(索引页和数据页)。我们对数据的操作,不是每次都直接操作磁盘,这样太慢了。innnoDB使用了一种缓冲池的技术,也即是把磁盘读到的每一页放到一块内存里面,这个区域就叫做Buffer Pool
  每次读取页的时候,先从缓存池中读取,如果缓存池中存在就直接读取,不再访问磁盘。
  修改数据的时候,先修改缓存池里的页。当磁盘和缓存池里的页数据不一致的时候,我们把它叫做脏页。InnoDB会有专门的线程,把buffer pool的数据写入到磁盘,每隔一段时间就把多个修改写入磁盘,这个动作就叫刷脏

3.2.InnoDB的内存和磁盘结构:https://dev.mysql.com/doc/refman/5.7/en/innodb-architecture.html
InnoDB Architecture
3.2.1.内存结构

1. Buffer Pool
 Buffer Pool缓存的是页信息,包括索引页和数据页,默认大小是128M(134217728字节),可以调整。当缓存池满了的时候,使用LRU算法来管理缓存池(链表实现,不是传统的LRU,分成了young和old),经过淘汰的数据之后剩下的就是热点数据。
2. change Buffer 写缓存
  在更新缓存的时候,如果在缓存中没有数据,就要从磁盘读取一次数据到缓存再更新,至少会发生一次io,所以为了避免这种情况,增加了一块change Buffer,如果这个数据页不是唯一索引,不需要考虑数据唯一性(否则就还是要跟磁盘的数据作比较,避免不了io操作),这种情况下可以先把修改记录在缓冲池中,从而提升语句(insert update delete)的执行速度。最后把Change Buffer 记录到数据页的操作叫merge,什么时候发生merge:在访问这个数据页的时候、或者通过后台线程、或者数据库shut down、redo log写满时触发。
  如果数据大部分索引时非唯一索引,并且业务时写多读少,不会在数据写后立即读取,就可以调大一点Change Buffer,默认是占Buffer Pool的25%。
3.Log Buffer(redo Log)
  如果buffer pool的脏页还没有刷新到磁盘时,数据库宕机或者重启,这些数据丢失。如果写到一半,甚至会破坏数据文件导致数据不可用。为了避免这个问题,innoDB把所有的写操作专门写入到一个日志文件,并且在数据库启动时从这个文件进行恢复操作(实现crash-safe)-用来实现事务的持久性。
  这个文件就是磁盘的redo Log,对应于/var/lib/mysql/目录下的ib_logfile0和ib_logfile1,每个大小48M
  这种日志和磁盘的配合过程,其实就是MySQL里面的WAL(Write Ahead Log),先写日志,再写磁盘。
  这里还有个知识点,写redo Log到磁盘是顺序IO,写数据到磁盘是随机io,所以写日志的速度更快。
  redo log buffer写入到磁盘的时机有3种选择,首先我们知道,内存往磁盘写数据中间时存在操作系统缓存的,flush就是把os cache刷到磁盘中。
show variables like 'innodb_flush_log_trx_commit'
默认是1,含义:https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit



总结一下redo Log的特点:

  1. redo Log是innoDB存储引擎实现的,不是所有存储引擎都有实现
  2. redo Log记录的是物理日志,不是记录每一行数据改了之后的状态,是记录数据页的改动。
  3. redo Log的大小是固定的,前面写的内容会被覆盖。


    图片.png

    checkpoint是当前要覆盖的位置。如果writepos跟checkpoint重叠,说明redo
    log已经写满,这时候需要同步redo log到磁盘中。

3.2.2.磁盘结构

  表空间可以看作是innoDB存储引擎逻辑层最高层,所有的数据都存放在表空间中。InnoDB的表空间分为5大类。
系统表空间 system table space
  主要包含双写缓冲,change buffer,undo log,如果没有指定file-per-table,也会包含用户创建的表。

  1. undo log(撤销日志或回滚日志)记录了事务发生之前的数据状态。
    如果修改数据时出现异常,可以用undo log来实现回滚操作(保持原子性)。
    在执行undo 的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,属于逻辑格式的日志。
    redo Log和undo Log与事务密切相关,统称为事务日志。
  2. 数据字典:由内部系统表组成,存储表和索引的元数据(定义信息)。
  3. 双写缓冲(InnoDB的一大特性):
    InnoDB的页和操作系统的页大小不一致,InnoDB页大小一般为16K,操作系统页大小为4K,InnoDB的页写入到磁盘时,一个页需要分4次写。

    如果存储引擎正在写入页的数据到磁盘时发生了宕机,可能出现页只写了一部分的情况,比如只写了4K,就宕机了,这种情况叫做部分写失效(partialpagewrite),可能会导致数据丢失。尽管我们已经有了redo log但是如果这个页已经损坏,那再恢复也是没意义的,因此我们应用redo log之前需要一个页的副本,如果出现了页的写入失效,则先还原这个页再应用redo log。这个页的副本就是double write,双写技术,通过它保证数据页的可靠性。
    有了这些日志之后,我们来总结一下一个更新操作的流程,这是一个简化的过程。
    name原值是qingshan。
    updateusersetname='penyuyan'whereid=1;
    1、事务开始,从内存或磁盘取到这条数据,返回给Server 的执行器;
    2、执行器修改这一行数据的值为penyuyan;
    3、记录name=qingshan到undo log;
    4、记录name=penyuyan到redo log;
    5、调用存储引擎接口,在内存(Buffer Pool)中修改 name=penyuyan;
    6、事务提交。
3.3.Binlog日志

  binlog以事件的形式记录了所有的DDL和DML语句(因为它记录的是操作而不是数据值,属于逻辑日志),可以用来做主从复制和数据恢复。
  跟redo log不一样,它的文件内容是可以追加的,没有固定大小限制。
  在开启了binlog功能的情况下,我们可以把binlog导出成SQL语句,把所有的操作重放一遍,来实现数据的恢复。
  binlog的另一个功能就是用来实现主从复制,它的原理就是从服务器读取主服务器的binlog,然后执行一遍。
有了这两个日志之后,我们来看一下一条更新语句是怎么执行的:


整体流程

1、先查询到这条数据,如果有缓存,也会用到缓存。
2、把name改成盆鱼宴,然后调用引擎的API接口,写入这一行数据到内存,同时记录redo log。这时 redo log 进入prepare 状态,然后告诉执行器,执行完成了,可以随时提交。
3、 执行器收到通知后记录binlog,然后调用存储引擎接口, 设置redolog为commit状态。
4、更新完成。

你可能感兴趣的:(MySQL进阶二(InnoDB存储引擎))