暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

多版本

我与风来 2021-06-28
282

本文翻译自 MySQL 官方文档。文字提到的很多知识点可能会很生疏,但在后续的文章中都会一一接触。那时,便明了了。

这篇文章与我们平常接触到的多版本控制(MVCC)可能不太一样,它更偏底层,也比较难理解。但在后续知识储备丰富以后,你会发现,平常我们所接触的知识,才是总结,而这些才是起因。

InnoDB 是一个多版本的存储引擎。它保留有关已更改行的旧版本的信息,以支持事务性功能,如并发和回滚。这些信息存储在名为 rollback segment
(回滚段) 的数据结构中的 undo 表空间中。InnoDB 使用回滚段中的信息执行事务回滚所需的撤销操作。它还使用这些信息构建行的早期版本,以实现一致性读取。

在内部,InnoDB 向数据库中的每一行添加三个字段:

  • 6 字节的 DB_TRX_ID
     字段表示插入或更新行的最后一个事务的事务标识符。删除在内部被视为更新,行中的特殊位置被设置为将其标记为已删除。

  • 7 字节的 DB_ROLL_PTR
     字段,称为滚动指针。滚动指针指向写入回滚段的 undo log 记录。如果行已更新,undo log 记录将包含在更新行之前重建行内容所需的信息。

  • 6 字节的 DB_ROW_ID
     字段包含一个随着新行插入而单调增加的行 ID。如果 InnoDB 自动生成聚集索引,则索引包含行 ID 值。否则,DB_ROW_ID
     列不会出现在任何索引中。

回滚段中的 undo log 被分为插入和更新 undo log。只有在事务回滚时才需要插入 undo log,并且可以在事务提交后立即丢弃。更新 undo log 也用于一致性读取,但只有在不存在 InnoDB 为其分配快照的事务时,才能丢弃更新 undo log。在一致性读取中,快照可能需要更新 undo log 中的信息来构建数据库行的早期版本。

建议定期提交事务,包括只发出一致读取的事务。否则,InnoDB 无法丢弃 更新 undo log
 中的数据,回滚段可能会变得太大,从而填满它所在的 undo 表空间。

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

在 InnoDB 多版本控制方案中,当您使用 SQL 语句删除某一行时,该行不会立即从数据库中物理删除。当 InnoDB 丢弃为删除而写的 更新 undo log
 记录时,它才在物理上删除相应的行及其索引记录。这个删除操作称为清除,它非常快,通常与执行删除操作的SQL语句的时间顺序相同。

如果在表中以大约相同的速率小批量插入和删除行,清除线程可能会开始落后,并且由于所有的“死”行,表可能会越来越大,从而使所有内容都被磁盘绑定并且速度非常慢。在这种情况下,通过调整 innodb_max_purge_lag
 系统变量来限制新行操作,并为净化线程分配更多资源。

多版本和二级索引

InnoDB 多版本并发控制(MVCC)处理二级索引的方式与处理聚集索引的方式不同。聚集索引中的记录会就地更新,它们的隐藏系统列指向撤消日志条目,从中可以重构记录的早期版本。与聚集索引记录不同,二级索引记录不包含隐藏的系统列,也不进行就地更新。

更新二级索引列时,旧的二级索引记录将被标记删除,新记录插入,标记删除的记录最终将被清除。当二级索引记录被标记删除或二级索引页被事务更新而更新时,InnoDB 在聚集索引中查找数据库记录。在聚集索引中,检查记录的 DB_TRX_ID
,如果在读取事务启动后修改了记录,则从 undo 日志检索记录的正确版本。

如果二级索引记录被标记为删除,或者二级索引页被较新的事务更新,则不使用覆盖索引技术。InnoDB 并不从索引结构返回值,而是在聚集索引中查找记录。

但是,如果启用了索引条件下推(ICP)优化,并且只能使用索引中的字段来计算 WHERE 条件的一部分,MySQL服务器仍然会将 WHERE 条件的这一部分下推到存储引擎中,在存储引擎中使用索引进行计算。如果找不到匹配的记录,则避免进行聚集索引查找。如果找到匹配的记录,即使在标记删除的记录中,InnoDB也会在聚集索引中查找该记录。


文章转载自我与风来,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论