【发布时间】:2010-08-27 13:18:26
【问题描述】:
在SQLite documentation关于3.7版本引入的预写日志功能中,有一些cmets让我有点困惑。
链接页面显示“不需要将内容同步到磁盘,只要应用程序愿意在断电后牺牲耐用性”。然后几段下来,它说“检查点确实需要同步操作,以避免断电或硬重启后数据库损坏的可能性”。
那么如果我使用 WAL,我的数据库是否会因断电而损坏的风险更大?
【问题讨论】:
标签: database sqlite corruption
在SQLite documentation关于3.7版本引入的预写日志功能中,有一些cmets让我有点困惑。
链接页面显示“不需要将内容同步到磁盘,只要应用程序愿意在断电后牺牲耐用性”。然后几段下来,它说“检查点确实需要同步操作,以避免断电或硬重启后数据库损坏的可能性”。
那么如果我使用 WAL,我的数据库是否会因断电而损坏的风险更大?
【问题讨论】:
标签: database sqlite corruption
要完整回答,我们需要知道您将PRAGMA synchronous 设置为什么,因为这会影响何时调用fdatasync(),从而影响何时刷新物理驱动器上的缓冲区。
当您引用“只要应用程序愿意在断电后牺牲耐用性”时,这是指拥有synchronous=NORMAL。这里 WAL 仅在检查点发生时同步到磁盘(一个 fdatasync() 用于 WAL,一个用于合并后的主数据库)。您应该很好地防止损坏,但可能有一些写入从未进入盘片并因此丢失:因此丢失了持久性。不过,实际同步数据的缓慢 fdatasync() 的好处要小得多。
为了最大限度地防止数据丢失,您可能需要synchronous=FULL。这重新获得了持久性,但成本是每个写入事务一个fdatasync()。但是,这仍然比非 WAL 模式要好,非 WAL 模式将有两个 fdatasync() 调用——一个用于事务日志,一个用于主数据库。
【讨论】:
WAL 不会增加损坏风险(因为它在检查点时使用同步操作)。
但是,如果发生崩溃(断电或硬重启),您将丢失自上次检查点以来的所有事务;这就是“牺牲耐用性”的意思。
【讨论】:
只要对您的操作系统的同步调用运行良好,您的数据库损坏的风险为零。然而,这可能是也可能不是——请参阅 sqlite 文档以获得更详细的解释。
纠正 Doug Currie(参见 MattR 的帖子):如果@synchronous=NORMAL@,您只会冒丢失交易的风险。如果@synchronous=FULL@(这是默认值),您不会牺牲持久性。请参阅http://www.sqlite.org/draft/wal.html 了解更多详情。
我相信 WAL 日志实际上比“经典”日志更安全(在系统同步不完美的情况下),因为据我了解 WAL 日志,数据库在给定时刻执行关键操作的机会较低。但是我目前没有确凿的数据来支持这一点。
【讨论】: