InnoDB 存储引擎浅析

InnoDB 存储引擎浅析

InnoDB 主要分为两大块:

  • InnoDB内存架构 (InnoDB In-Memory Structures)
  • InnoDB磁盘架构 (InnoDB On-Disk Structures)

InnoDB 内存架构

  1. Buffer Pool

    • 当我们执行dml语句时,mysql不会直接去修改磁盘数据,因为这样做太慢了,mysq会先改内存,然后记录redolog和binlog(redolog和binlog采用两阶段提交机制,确保binlog写入完整性进而保证主从架构的从库数据完整性,redolog主要用于mysql的cash_safe机制,即崩溃时未及时刷盘的内存数据的恢复),等有空了再进行刷盘,如果内存没有数据, mysql不会立即去磁盘load,而是先把修改记录到change buffer的地方,等到有select语句,查询该数据时,才会load磁盘,然后将change buffer merge到buffer pool, 而这些数据存放的地方就是Buffer Pool
    • MySQL 是以页(page)为单位从磁盘读取数据的,Buffer Pool 里的数据也是如此,实际上,Buffer Pool 是a linked list of pages,一个以页为元素的链表,毕竟内存空间是有限的,所以mysq的缓存也需要一种内存淘汰算法,正是基于LRU的算法来管理内存
    • Buffer Pool 采用基于LRU的算法来管理内存,为什么是基于LRU,肯定是原生LRU算法有不合适的地方(比如,我们在进行全表扫描或者大数据量查询的时候,其实有些数据我们只是当前用一次,之后就很少访问了,但是由于数据量巨大,导致我们正常的热点数据被LRU淘汰,导致缓存利用率不高甚至失效),于是mysql基于自身进行了修改。mysql维护了两个lru链表,其中newList占总长度5/8, oldList占总长度3/8,其中newList是热点数据,oldList中的数据需要访问频率和对象存活时间等条件都满足之后,才会进入到newList,newList执行正常的LRU淘汰算法,此时当我们进行全表扫描或者大数据量查询的时候,就只会占用3/8的lru链表,另外5/8永远是真正的热点数据
  2. Change Buffer

  • 上面提到过,如果内存里没有对应「页」的数据,MySQL 就会去把数据从磁盘里 load 出来,如果每次需要的「页」都不同,或者不是相邻的「页」,那么每次 MySQL 都要去 load,这样就很慢了。

  • 于是如果 MySQL 发现你要修改的页,不在内存里,就把你要对页的修改,先记到一个叫 Change Buffer 的地方,同时记录 redo log,然后再慢慢把数据 load 到内存,load 过来后,再把 Change Buffer 里记录的修改,应用到内存(Buffer Pool)中,这个动作叫做 merge;而把内存数据刷到磁盘的动作,叫 purge:

  • Change Buffer 只在操作「二级索引」(secondary index)时才使用,原因是「聚簇索引」(clustered indexes)必须是「唯一」的,也就意味着每次插入、更新,都需要检查是否已经有相同的字段存在,也就没有必要使用 Change Buffer 了;另外,「聚簇索引」操作的随机性比较小,通常在相邻的「页」进行操作,比如使用了自增主键的「聚簇索引」,那么 insert 时就是递增、有序的,不像「二级索引」,访问非常随机。

  1. log buffer

    • log buffer 是mysql记录redolog的地方,我们知道redolog是写入磁盘的,那为什么mysql修改数据不直接改磁盘数据呢,接下来谈谈redolog机制。

    • mysql修改数据是随机写的,磁盘的随机写(磁盘寻址,磁头的物理旋转到指定位置)是非常耗时的,而redolog写磁盘是顺序写,redolog采用了一种循环写的文件结构,节省空间,并且磁盘顺序写的性能是很高的。

  2. redolog 和 binlog

    • redolog是一种物理日志,记录的是磁盘页数据的修改情况,而binlog是逻辑日志。
    • binlog分3中模式(row模式记录每行数据的修改情况(耗费存储空间,可以保证主从数据完全一致),statement模式可以理解为记录的就是sql语句(节省空间,但不能保证主从数据完全一致,比如sql语句中有now()函数,生成当前时间等字段),混合模式,即mysql会根据每个sql语句的情况,选择采用row还是statement模式进行记录。
  3. 自适应哈希索引 Adaptive Hash Index

    • MySQL 索引,不管是在磁盘里,还是被 load 到内存后,都是 B+ 树,B+ 树的查找次数取决于树的深度, 为了进一步提高查询效率,MySQL 会自动评估使用自适应索引是否值得(用一个指针把数据的位置记录下来),如果观察到建立哈希索引可以提升速度,则建立。

InnoDB 磁盘架构

  1. 表空间
  • Tablespaces 分为五种:
    The System Tablespace
    File-Per-Table Tablespaces
    General Tablespace
    Undo Tablespaces
    Temporary Tablespaces
    其中,我们平时创建的表的数据,可以存放到 The System Tablespace 、File-Per-Table Tablespaces、General Tablespace 三者中的任意一个地方,具体取决于你的配置和创建表时的 sql 语句。
  1. Doublewrite Buffer

    • MySQL 以「页」为读取和写入单位,一个「页」里面有多行数据,写入数据时,MySQL 会先写内存中的页,然后再刷新到磁盘中的页。

    这时问题来了,假设在某一次从内存刷新到磁盘的过程中,一个「页」刷了一半,突然操作系统或者 MySQL 进程奔溃了,这时候,内存里的页数据被清除了,而磁盘里的页数据,刷了一半,处于一个中间状态,不尴不尬,可以说是一个「不完整」,甚至是「坏掉的」的页。

    你可能会说,不是有 Redo Log 么?其实这个时候 Redo Log 也已经无力回天,Redo Log 是要在磁盘中的页数据是正常的、没有损坏的情况下,才能把磁盘里页数据 load 到内存,然后应用 Redo Log。而如果磁盘中的页数据已经损坏,是无法应用 Redo Log 的。

    所以,MySQL 在刷数据到磁盘之前,要先把数据写到另外一个地方,也就是 Doublewrite Buffer,写完后,再开始写磁盘。Doublewrite Buffer 可以理解为是一个备份(recovery),万一真的发生 crash,就可以利用 Doublewrite Buffer 来修复磁盘里的数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值