如果有重做日志和撤消日志,为什么MySQL需要双写缓冲区?

Why does MySQL need double-write buffer if there is redo log and undo log?

提问人:user855 提问时间:11/17/2023 更新时间:11/17/2023 访问量:21

问:

此问题是从 Stack Overflow 迁移而来的,因为它可以在 Database Administrators Stack Exchange 上找到答案。3 天前迁移

如果有重做日志和撤消日志,为什么MySQL需要双写缓冲区?

我阅读了其他帖子,这些帖子回答了为什么MySQL需要双写缓冲区。他们指向这篇文章。http://dimitrik.free.fr/blog/archives/2011/01/mysql-performance-innodb-double-write-buffer-redo-log-size-impacts-mysql-55.html

并且无法从重做日志中修复它,因为重做中仅保存了更改,而不是整个页面

该文章陈述了上述内容。但我仍然不明白为什么。

每个页面的块都包含应用于它的 LSN。不是吗?因此,即使由于部分页面写入而仅将页面的某些块写入磁盘,我也可以查看与每个块关联的 LSN,并检测它是否为部分写入。如果是部分写入,我将重播该 LSN 的重做记录。重播将为我提供更新的字节集,以修补到给定的偏移范围,并将其应用于以前未应用 LSN 的块。

这行不通吗?为什么需要双写入缓冲区?

假设上述方法不起作用。但是我仍然可以使用撤消日志,对吗?我可以看到页面已部分更新,从撤消日志中获取旧值并应用它来回滚事务。

重做日志如何保证单个日志记录在跨越块边界时不会部分写入磁盘?

实际上,我无法弄清楚的是,由于单个重做日志记录可以跨越块边界,因此重做日志使用什么机制来检测重做记录未完全写入并将日志截断为最后一个已知的完整日志记录,而不是应用部分日志记录?

MySQL

评论


答:

0赞 Bill Karwin 11/17/2023 #1

一个页面可以包含多条记录。事实上,它至少需要包含两条记录。

重做日志不是页面的副本,而是对特定记录的更改日志。

因此,如果原始页面在部分页面写入中损坏,则重做日志无法重建该页面上的其他记录。

示例:重做日志包含有关对一条记录的更改的信息,该记录存储在缓冲池的修改页面中。这就像应用于页面的“差异”。当需要从缓冲池中刷新该页面时,会发生一些事情,使页面写入部分失败。例如,磁盘击中了损坏的扇区,或者mysqld进程被杀死或类似的东西。因此,如果mysqld重新启动并且缓冲池中的脏页面丢失,则崩溃恢复必须从磁盘读取原始页面,然后将重做日志“diff”应用于该页面。但它不能 - 原始页面被部分覆盖,因此差异没有起点。

撤消日志是原始页面的副本,但在计划将页面从缓冲池刷新到表空间时,它可能已被清除。

撤消日志条目仅在允许回滚或支持处于可重复读取隔离级别的其他打开事务时才需要。关闭需要查看“撤消日志”条目内容的最后一个事务后,可以清除该“撤消日志”条目。与这些撤消日志条目对应的页面修改可以作为“脏页”在缓冲池中保留更长的时间,直到需要刷新它们为止。

评论

0赞 user855 11/17/2023
> 因此,如果原始页面在部分页面写入中损坏,则重做日志无法重建该页面上的其他记录。--- 您能否举例说明这种情况发生的情况?这是我不明白的部分。
0赞 user855 11/17/2023
> 撤消日志是原始页面的副本,但在计划将页面从缓冲池刷新到表空间时,它可能已被清除 -- 为什么?
0赞 Bill Karwin 11/17/2023
我已经写了更多来解释它。