FantasticMao 技术笔记
BlogGitHub
  • README
  • C & Unix
    • C
      • 《C 程序设计语言》笔记
      • C 语言中的陷阱
      • CMake 示例
      • GNU make
      • LLVM Clang
      • Nginx 常用模块
      • Vim 常用命令
    • Unix-like
      • 《深入理解计算机系统》笔记
      • 《UNIX 环境高级编程》笔记 - UNIX 基础知识
      • 《UNIX 环境高级编程》笔记 - 文件 IO
      • 《UNIX 环境高级编程》笔记 - 标准 IO 库
      • 《鳥哥的 Linux 私房菜》笔记 - 目录配置
      • 《鳥哥的 Linux 私房菜》笔记 - 认识与学习 bash
      • 《鳥哥的 Linux 私房菜》笔记 - 任务管理
      • OpenWrt 中的陷阱
      • iptables 工作机制
  • Go
    • 《A Tour of Go》笔记
    • Go vs C vsJava
    • Go 常用命令
    • Go 语言中的陷阱
  • Java
    • JDK
      • 《Java 并发编程实战》笔记 - 线程池的使用
      • 设计模式概览
      • 集合概览
      • HashMap 内部算法
      • ThreadLocal 工作机制
      • Java Agent
    • JVM
      • 《深入理解 Java 虚拟机》笔记 - Java 内存模型与线程
      • JVM 运行时数据区
      • 类加载机制
      • 垃圾回收算法
      • 引用类型
      • 垃圾收集算法
      • 垃圾收集器
    • Spring
      • Spring IoC 容器扩展点
      • Spring Transaction 声明式事务管理
      • Spring Web MVC DispatcherServlet 工作机制
      • Spring Security Servlet 实现原理
    • 其它
      • 《Netty - One Framework to rule them all》演讲笔记
      • Hystrix 设计与实现
  • JavaScript
    • 《写给大家看的设计书》笔记 - 设计原则
    • 《JavaScript 权威指南》笔记 - jQuery 类库
  • 数据库
    • ElasticSearch
      • ElasticSearch 概览
    • HBase
      • HBase 数据模型
    • Prometheus
      • Prometheus 概览
      • Prometheus 数据模型和指标类型
      • Prometheus 查询语法
      • Prometheus 存储原理
      • Prometheus vs InfluxDB
    • Redis
      • 《Redis 设计与实现》笔记 - 简单动态字符串
      • 《Redis 设计与实现》笔记 - 链表
      • 《Redis 设计与实现》笔记 - 字典
      • 《Redis 设计与实现》笔记 - 跳跃表
      • 《Redis 设计与实现》笔记 - 整数集合
      • 《Redis 设计与实现》笔记 - 压缩列表
      • 《Redis 设计与实现》笔记 - 对象
      • Redis 内存回收策略
      • Redis 实现分布式锁
      • Redis 持久化机制
      • Redis 数据分片方案
      • 使用缓存的常见问题
    • MySQL
      • 《高性能 MySQL》笔记 - Schema 与数据类型优化
      • 《高性能 MySQL》笔记 - 创建高性能的索引
      • 《MySQL Reference Manual》笔记 - InnoDB 和 ACID 模型
      • 《MySQL Reference Manual》笔记 - InnoDB 多版本
      • 《MySQL Reference Manual》笔记 - InnoDB 锁
      • 《MySQL Reference Manual》笔记 - InnoDB 事务模型
      • B-Tree 简述
      • 理解查询执行计划
  • 中间件
    • gRPC
      • gRPC 负载均衡
    • ZooKeeper
      • ZooKeeper 数据模型
    • 消息队列
      • 消息积压解决策略
      • RocketMQ 架构设计
      • RocketMQ 功能特性
      • RocketMQ 消息存储
  • 分布式系统
    • 《凤凰架构》笔记
    • 系统设计思路
    • 系统优化思路
    • 分布式事务协议:二阶段提交和三阶段提交
    • 分布式系统的技术栈
    • 分布式系统的弹性设计
    • 单点登录解决方案
    • 容错,高可用和灾备
  • 数据结构和算法
    • 一致性哈希
    • 布隆过滤器
    • 散列表
  • 网络协议
    • 诊断工具
    • TCP 协议
      • TCP 报文结构
      • TCP 连接管理
由 GitBook 提供支持
在本页
  • 多版本
  • 多版本和二级索引
  • 参考资料
  1. 数据库
  2. MySQL

《MySQL Reference Manual》笔记 - InnoDB 多版本

最后更新于1年前

本篇文章记录自己在阅读 MySQL Reference Manual 时候,关于 InnoDB 多版本的一些笔记。

多版本

InnoDB 是一个 :它会保留已更改行的旧版本信息,用于支持事务的特性,例如并发和回滚。这些信息以被称为 (一种与 Oracle 中类似的数据结构)的数据结构存储在表空间中。InnoDB 使用回滚段中的信息来执行在事务回滚中所需要的回滚操作。它还会使用这些信息来构建行的早期版本,用于实现一致性读取。

InnoDB 会在内部为存储于数据库中的每行添加三个字段。一个 6 字节的 DB_TRX_ID 字段,用于表示插入或更新该行的最后一次事务的事务标识符。此外,删除操作在内部会被视为更新操作,此时该行中的一个特殊位会被标记成已删除。每行还包含了一个 7 字节的 DB_ROLL_PTR 字段,被称为滚动指针。滚动指针指向了一条写在回滚段中的撤销日志(undo log)记录。如果该行被更新了,那么包含了信息的撤销日志记录可以在必要的时候,把该行的内容重建到它被更新之前的版本。一个 6 字节的 DB_ROW_ID 字段,包含了一个行的 ID,会随着插入新行而单调增加。如果 InnoDB 自动生成了聚簇索引,那么该索引会包含行的 ID 值。否者,DB_ROW_ID 不会出现在任何索引中。

回滚段中的撤销日志分为插入和更新的撤销日志。插入撤销日志只会在事务回滚时被需要,并且在事务提交后可以被立即丢弃。更新撤销日志会被用于一致性读取,但仅当在没有 InnoDB 为已经分配了的快照(在一致性读取中,可能需要这个更新撤销日志中的快照信息来构建数据库行的早期版本)而存在的事务之后,才可以丢弃它们。

建议经常提交你的事务,包括仅会发出一致性读取的事务。否则,InnoDB 不会丢弃更新撤销日志中的数据,并且回滚段可能会变得太大从而填满了表空间。

回滚段中的撤销日志记录的物理大小通常小于它对应的插入或者更新的行。你可以使用这个信息来计算回滚段所需的空间大小。

在 InnoDB 多版本的体系中,当你使用 SQL 语句删除行的时候,该行并不会被立即从数据库中物理删除。当 InnoDB 丢弃为删除操作而写入的更新撤销日志记录的时候,它只会物理删除对应的行和索引记录。这个删除操作被称为 ,它运行速度非常快,通常会和执行删除操作的 SQL 语句所花费的时间相同。

如果你在表中以大约相同的速率,小批量地插入和删除行的时候,清除线程可能会落后于创建线程,并且表空间可能会由于这些「死」行而变得越来越大,从而使所有内容都受到磁盘的约束,变得非常缓慢。在这种情况下,请限制插入新行的操作,并通过调整 innodb_max_purge_lag 系统变量来为清除线程分配更多资源。更多内容请见 。

多版本和二级索引

InnoDB 的多版本并发控制(multiversion concurrency control,MVCC)对待二级索引的处理方式与对待聚簇索引的方式不同。聚簇索引中的记录会被就地更新,并且它们所隐藏的系统列指向了撤销日志中的条目,这些条目可以被用于重建早期版本的记录。与聚簇索引不同的是,二级索引不包含隐藏的系统列,也不会就地更新记录。

当二级记索引列被更新的时候,旧的二级索引记录会被标记成删除,新的记录会被插入,并且被标记删除的记录最终会被清除。当二级索引记录被标记成删除或者二级索引页被更(gèng)新的事务所更(gēng)新的时候,InnoDB 会在聚簇索引上查找数据库中的记录。在聚簇索引中,记录的 DB_TRX_ID 字段会被检查,并且会从撤销日志中检索记录的正确版本,如果记录在读取事务初始化之后被修改了的话。

如果二级索引记录被标记成删除或者二级索引页被更新的事务所更新了,那么 技术不会被使用。InnoDB 不会从索引结构中返回值,而是会在聚簇索引中查找记录。

然而,如果开启了 优化,并且 WHERE 条件的一部分可以使用索引结构中的字段来被评估,那么 MySQL 服务会将 WHERE 条件的一部分下推给存储引擎,存储引擎会使用索引来进行评估。如果没有匹配到记录,那么在聚簇索引的查找可以被避免。如果匹配到了记录,那么 InnoDB 会在聚簇索引上查找记录,即使是在被标记删除的记录中。

参考资料

多版本的存储引擎
回滚段
清除
InnoDB Startup Options and System Variables
覆盖索引
索引条件下推(index condition pushdown,ICP)
InnoDB Multi-Versioning