Featured image of post InnoDB 存储引擎

InnoDB 存储引擎

事务

事务是一组逻辑上的数据库操作,这些操作要么全部成功,要么全部失败。

  • A 原子性:事务是不可分割的最小操作单元,要么全部成功,要么全部失败。

  • C 一致性:事务完成时,必须使所有的数据都保持一致状态。

  • I 隔离性:数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。

  • D 持久性:事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

1

C(一致性)是目的,A(原子性)、I(隔离性)、D(持久性)是是为了保证一致性,数据库提供的手段。

🔃 redo log

重做日志,记录的是“某个数据页上做了什么修改”。(物理日志)

redo log 用来保障数据库的持久性。在一个事务中,执行增删改的操作时,InnoDB 引擎会先操作缓冲池 Buffer Pool 中的数据,如果缓冲区没有对应的数据,会通过后台线程将磁盘中的数据加载出来,存放在缓冲区中,再将缓冲池中的数据修改。

redolog

修改后的数据页我们称为脏页,缓冲区的脏页数据并不是实时刷新的,而是一段时间之后将缓冲区的数据刷新到磁盘中(随机磁盘 IO),从而保证缓冲区与磁盘的数据一致。

对缓冲区的数据进行增删改,会首先将操作的数据页的变化,记录在 redo log buffer 中。在事务提交时,将 redo log buffer 中的数据刷新到 redo log 磁盘文件中(顺序磁盘 IO)。

如果刷新缓冲区的脏页到磁盘时发生错误,或者发生了异常断电,就可以借助于 redo log 进行数据恢复,这样就保证了事务的持久性。

🔙 undo log

回滚日志。记录操作数据库的逆操作,用于进行回滚。

作用:

  • 提供回滚操作(保障事务的原子性)
  • 实现 MVCC 操作,提升数据库性能

undo log 是逻辑日志,在 InnoDB 存储引擎对记录进行修改时,会把回滚需要的信息全部记录到 undo 中,如果发生回滚,就会读取 undo log,然后执行与之相反的操作。

  • ➕ 插入数据,记录这条数据的主键,回滚时根据主键把该条记录删除

  • ➖ 删除数据,记录这条数据的所有内容,回滚时将这些内容组成的记录插入表中

  • 🖋️ 更新数据,

    • 更新了主键,会记录两条 undo log,一条删除的,一条更新的
    • 没有更新主键,记录这条数据更新列的旧值,回滚时将数据更新为旧值

📔 MVCC

多版本并发控制,同一条记录在数据库中,可以存在多个版本。

依赖于:

  • 行的隐式字段
    • DB_TRX_ID 事务 id
    • DB_ROLL_PTR 回滚指针(记录这条记录的上一个版本)
  • undo log
  • Read View

2

当前读

读取的是记录的最新版本。

update insert delete select ... for update select ... lock in share mode 都是进行当前读。

快照读

简单的不加锁 select 就是快照读。读取的是快照版本,通过 MVCC 进行并发控制。

🚀 关键特性

InnoDB 存储引擎的特性,可以带来更高的性能和可靠性。

🧮 插入缓冲 Insert Buffer

当插入一条数据的时候,在聚簇索引中,通常数据都是在叶子节点顺序存放的,只需要将插入的数据放到最后即可(主键顺序存放)。

通常我们都会在一张表上创建一些二级索引,而这些二级索引在数据插入时,需要维护索引是离散的,由于随机 IO 就会导致插入性能的下降。

为了解决以上问题,InnoDB 设计了 Insert Buffer

二级索引的更新操作:

  • 如果需要更新的索引页在 Buffer Pool 中,则直接插入;
  • 如果不在,则插入 Insert Buffer,之后以一定的频率和情况在与二级索引合并

使用 Insert Buffer 需要满足两个条件:

  • ⭐ 二级索引
  • ⭐ 非唯一索引

如果二级索引是唯一的,在插入时,还需要去索引页查找改索引是否唯一,这样的离散读取两部分,会导致 Insert Buffer 失去意义。

后续的版本提供了升级版本 Change Buffer,对 Insert、Delete、Update 都进行缓冲。

🖋️ 两次写 Double Write

InnoDB 将脏页刷新到磁盘中时,突然发生宕机,只写入了一半,可能会发生数据丢失的问题。

InnDB 使用 Double Wirte 机制,给数据添加副本,防止数据丢失。

需要刷新的脏页会被复制到 Double Write Buffer 中,在需要刷盘时:

  • 先分两次写入一份到共享表空间的 double wirte 物理磁盘上(顺序写入)
  • 再将数据同步到磁盘中(随机 IO)

🗂️ 自适应哈希索引

InnoDB 存储引擎会自动根据访问的频率和模式给热点数据建立一个 Hash 索引,加快读请求。

只能为等值查询建立,范围查询不能建立。

📖 预读机制

InnoDB 会将查询页的邻近页一起读到 Buffer Pool 中。

通过改进的 LRU 链表(管理干净页 & 脏页的链表),解决了预读失效的问题。。

Licensed under CC BY-NC-SA 4.0