InnoDB 底层原理

InnoDB更新语句及日志底层原理

更新语句整体执行流程在这里插入图片描述

undo log

undo log 作用
如果事务提交失败,数据要回滚,利用 undo log 恢复 Buffer Poll 缓存中的数据。

redo log

redo log 和 idb 文件 写入方式对比
redo log 写入方式是磁盘顺序写,即首先为日志文件分配好磁盘空间,每次的更新语句在文件末尾追加。

idb 文件的写入方式是随机写,因为每张表对应一个 idb 文件,当有多条更新 sql 语句,要修改不同的表时,由于 idb 文件存放顺序不确定,也就不能顺序写。

redo log 作用
当 Buffer Pool 缓存池中的文件还没来得及更新到 ibd 磁盘文件中,系统宕机了,这时可以利用 redo log 文件恢复 ibd 文件内容。

redo log 写入磁盘过程分析
redo log 文件可能不止一个,这些文件是首尾相连的,写入时从第一个文件开始写,写完一个文件继续写另一个文件,写到最后一个文件末尾就又回到第一个文件开头循环写,如下面这个图所示。

在这里插入图片描述
如果 write pos 追上了 check point,这时要把文件中的一部分内容持久化道磁盘中,为后续的写入清出一定的空间。

redo log 日志关键参数
innodb_log_buffer_size: 设置redo log buffer大小参数,默认16M ,最大值是4096M,最小值为1M。

show variables like '%innodb_log_buffer_size%';

innodb_log_group_home_dir: 设置redo log文件存储位置参数,默认值为"./",即innodb数据文件存储位置,其中的 ib_logfile0 和 ib_logfile1 即为redo log文件。

show variables like '%innodb_log_group_home_dir%';

innodb_log_file_size: 设置单个redo log文件大小,默认值为48M。最大值为512G,注意最大值指的是整个 redo log系列文件之和,即(innodb_log_files_in_group * innodb_log_file_size)不能大于最大值512G。

show variables like '%innodb_log_file_size%';

innodb_flush_log_at_trx_commit: 控制 redo log 的写入策略,有三种值。

  • 0:每次事务提交时,只把日志信息保存到 redo log buffer 中,如果数据库宕机可能会丢数据。
  • 1:每次提交事务时,直接把日志信息持久化到磁盘,性能稍微低点,但是数据一定不会丢失,线上环境推荐用这个。
  • 2:每次事务提交把日志信息写到操作系统的内存 page cache 中。如果数据库宕机,数据不会丢失,但是如果操作系统宕机了,page cache 中的数据还没有保存到磁盘中,数据就会丢失。
show variables like 'innodb_flush_log_at_trx_commit';

InnoDB 有一个后台线程,每隔一秒会利用 write 函数把 redo log buffer 中的数据保存到 page cache 中,再由操作系统使用 fsync 函数把数据持久化到磁盘中。所以当 innodb_flush_log_at_trx_commit 的值为 2 时,操作系统会把 page cache 中的数据持久化到磁盘中。

bin log

binlog 使用
MySQL5.7版本默认关闭,可以通过以下配置来开启

# log-bin设置binlog的存放位置,可以是绝对路径,也可以是相对路径,这里写的相对路径,则binlog文件默认会放在data数据目录下
log-bin=mysql-binlog
# Server Id是数据库服务器id,随便写一个数都可以,这个id用来在mysql集群环境中标记唯一mysql服务器,集群环境中每台mysql服务器的id不能一样,不加启动会报错
server-id=1
# 其他配置
binlog_format = row # 日志文件格式,下面会详细解释
expire_logs_days = 15 # 执行自动删除距离当前15天以前的binlog日志文件的天数, 默认为0, 表示不自动删除
max_binlog_size = 200M # 单个binlog日志文件的大小限制,默认为 1GB

查看 binlog 相关信息

show variables like '%log_bin%';

查看有多少个文件

show binary logs;

binlog 作用
1、保存所有执行过的修改数据的语句,当不小心删除了表中的数据,可以通过 binlog 来恢复。
2、主从复制功能也可以通过 binlog 来实现。

binlog 日志关键参数

binlog_format: 设置日志记录格式,有三个值。

  • STATEMENT:记录 sql 语句,缺点是例如对于 UUID()、SYSDATE()等函数的结果和之前执行的不一样。
  • ROW:记录更新后的那条数据信息,例如一个 sql 语句更新了十条数据,那么这种记录方式就会记录这十条数据。缺点是记录内容多。
  • MIXED:混合模式。如果 sql 语句中包含只有在执行时才知道结果的情况就用 ROW,否则用 STATEMENT。

sync_binlog: 写入磁盘机制,也有三个值可以选择。

  • 0:每次提交事务后把数据保存到 page cache 中,由系统决定什么时候写到磁盘中。
  • 1:每次提交数据都会把数据写入磁盘,这种最安全。
  • N(>1):每次提交事务后把数据保存到 page cache 中,保存到 N 个事务之后写入磁盘。

查看 binlog 日志文件

# 查看bin-log二进制文件(命令行方式,不用登录mysql)
mysqlbinlog --no-defaults -v --base64-output=decode-rows D:/dev/mysql-5.7.25-winx64/data/mysql-binlog.000007 

# 查看bin-log二进制文件(带查询条件)
mysqlbinlog --no-defaults -v --base64-output=decode-rows D:/dev/mysql-5.7.25-winx64/data/mysql-binlog.000007 start-datetime="2023-01-21 00:00:00" stop-datetime="2023-02-01 00:00:00" start-position="5000" stop-position="20000"
### InnoDB底层实现原理及工作机制 #### 1. 持久性与一致性 InnoDB通过WAL(Write-Ahead Logging)机制来确保数据的一致性和持久性。在写入磁盘之前,先将操作记录写入重做日志(redolog),这样即使数据库发生崩溃,重启时也可以通过重做日志恢复未完成的事务[^1]。此外,重做日志保证了InnoDB的crash-safe能力,即即使系统崩溃,已提交的数据也不会丢失[^2]。 #### 2. 行锁机制 InnoDB支持行级锁定,这有助于提高并发性能。行锁能够减少锁定范围,避免表级锁定带来的性能问题。行锁的实现依赖于聚簇索引和二级索引结构[^4]。当事务需要对某一行进行修改时,InnoDB会通过B+树索引定位到具体的行,并对其加锁,从而允许其他事务同时访问不受影响的行[^5]。 #### 3. 聚簇索引与存储结构 InnoDB使用聚簇索引来组织数据存储。聚簇索引将主键与实际数据存储在一起,这意味着主键索引的叶子节点中包含了完整的行数据。由于数据只保存一份,因此聚簇索引只能有一个,而二级索引的叶子节点则存储主键值以指向聚簇索引中的具体行[^4]。 #### 4. 事务支持与崩溃恢复 InnoDB支持ACID事务特性。为了实现这一目标,InnoDB引入了undo log和redo log两种日志机制。Redo log用于记录数据的物理修改,确保数据持久化;Undo log则用于支持事务的回滚以及多版本并发控制(MVCC)。当事务需要回滚时,InnoDB会利用undo log撤销已经执行的操作[^1]。 #### 5. 缓冲池与内存管理 InnoDB通过缓冲池(Buffer Pool)来缓存数据页和索引页,从而减少磁盘I/O开销。缓冲池中的数据页按照LRU算法进行管理,常用的数据页会被保留在内存中,而不常用的数据页则可能被置换出去。此外,InnoDB还实现了双写缓冲(Doublewrite Buffer),以防止部分写失败导致的数据页损坏。 #### 6. 多版本并发控制(MVCC) 为了提高读写并发性能,InnoDB实现了多版本并发控制(MVCC)。在读取数据时,InnoDB会根据事务的隔离级别生成数据的快照版本,从而避免读写冲突。MVCC的核心是通过隐藏列(如事务ID和回滚指针)来维护不同版本的数据行[^3]。 #### 7. 主键与外键约束 InnoDB强制要求每张表必须有主键,如果没有显式定义主键,则会自动创建一个隐式的6字节主键。此外,InnoDB支持外键约束,可以确保引用完整性,而MyISAM则不支持外键[^3]。 ```python # 示例:创建带有主键和外键的InnoDB表 CREATE TABLE parent ( id INT NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB; CREATE TABLE child ( id INT NOT NULL, parent_id INT NOT NULL, PRIMARY KEY (id), CONSTRAINT fk_parent FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ) ENGINE=InnoDB; ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值