【MySQL】InnoDB存储引擎架构设计 |周末学习

「本文已参与 周末学习计划,点击查看详情

这是我参与更文挑战的第6天,活动详情查看:更文挑战

一、前言

场景:存储引擎完成一条更新语句的执行。

InnoDB 的重要内存结构:缓冲池(Buffer Pool

这里面会缓存很多的数据,以便于以后在查询的时候,万一要是内存缓冲池里有数据,就可以不用去查磁盘了。

如图:

mysql-1.png

二、举个栗子:

执行更新 SQL,会发生什么呢?

UPDATE user SET name = 'donaldy' WHERE id=10;
复制代码

步骤:

  1. 缓冲池中数据操作
  2. undo 日志文件:保存旧值
  3. redo log buffer:保存新值
  4. 后台线程不定时刷新内存里的数据到磁盘文件里。

为什么不直接更新磁盘上的数据?

因为执行性能极差。
来一个请求就直接对磁盘文件进行随机读写,然后更新磁盘文件里的数据,虽然技术上可以实现,但导致执行请求的性能极差。

所以 MySQL 才设计了这样复杂的一套机制,通过内存里更新数据,然后写 redo log 以及事务提交,后台线程不定时刷新内存的数据到磁盘文件中。

1)缓冲池中数据操作

概括:将数据从磁盘读取,放到内存中操作,操作完成后,再写入磁盘

详细步骤如下:

  1. 查看 id=10这一行数据是否在缓冲池里
  2. 若缓冲池有,则会对这行记录加独占锁
  3. 若不在的话,会直接从磁盘里加载到缓冲池里来
  4. 操作完成后,写入磁盘

问题:为什么用独占锁?

保证原子操作

2)undo 日志文件:保存旧值

如图:

mysql-2.png

旧值:更新之前的值

# 原先数据:id = 10, name = 'gege'

# 执行SQL
UPDATE user SET name = 'donaldy' WHERE id=10;

# 那么 'gege' 就是旧值
复制代码

为什么要保存旧值?

为了方便之后回滚,旧值恢复。

3)redo log buffer:保存新值

万一系统宕机了,内存中数据丢失了,怎么办?

这时候要把内存中所做的修改写入到一个 Redo Log Buffer里去,这是内存里的一个缓冲区,用来存放 redo 日志的。

功能:其实是用来在 MySQL 突然宕机的时候,用来恢复更新过的数据。

问题:如果还没提交事务,MySQL 宕机了怎么办?

此问题分三种情况:

  • 事务提交之前
  • 事务提交之中
  • 事务提交成功

  1. 事务提交之前:

还没有提交事务,此时 MySQL 崩溃了,必然导致内存里 Buffer Pool中的修改过的数据都丢失,同时写入 Redo Log Buffer 中的 redo 日志也会丢失。
没提交事务,就代表没执行成功,此时 MySQL 宕机虽然导致内存里的数据都丢失了,但磁盘上的数据依然还停留在原样子。
所以,此时如果 MySQL 宕机,不会有任何的问题。

  1. 事务提交之中:

前置:提交一个事务,此时会根据一定的策略把 redo日志从 redo log buffer 里刷入到磁盘文件里。

这个策略通过 innodb_flush_log_at_trx_commit 来配置的。

  • 参数值为 0 时,不会把 redo log buffer 里的数据刷入磁盘文件,此时提交事务,MySQL 宕机,内存里的数据全部丢失。
  • 参数值为 1 时,就必须把 redo log 从内存刷入磁盘文件里去,只要事务提交成功,那么 redo log必然在磁盘里。
  • 参数值为 2 时,提交事务的时候,把 redo 日志写入磁盘文件对应的 os cache 内存缓存里,没实际进入磁盘文件,万一此时要是机器宕机了,那么 os cache 里的 redo log 就会丢失; 即提交事务成功,而数据丢失了。

如图:

mysql-3.png

所以根据参数值,不同会有不同结果。

  1. 事务提交成功:

如上,会根据 innodb_flush_log_at_trx_commit 参数值,而会有不同结果

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享