我有一个奇怪的问题,与核心数据在iOS应用程序,有时WAL文件变得 * 巨大 *(~1GB)。它似乎有其他人的问题(eidogg. Core Data sqlite-wal file gets MASSIVE (>7GB) when inserting ~5000 rows)。
我最初的想法是在应用程序启动时删除WAL文件。从阅读sqlite文档来看,这似乎没问题。但有人知道这样做的缺点吗?
我当然想弄清楚为什么WAL文件会变得这么大,但是我现在不能弄清楚,我想在深入研究这个问题的同时找到一个解决方法。
值得指出的是,我的Core Data数据库更像是一个缓存。因此,如果我丢失了WAL中的数据,也没关系。我真正需要知道的是,如果我删除WAL,数据库是否会完全损坏?我的怀疑是否定的,否则WAL就无法发挥其作用。
6条答案
按热度按时间r6hnlfcb1#
几件事:
1.当然,您可以删除WAL文件,因为您将丢失所有未被检查点返回到主文件的已提交事务(因此违反了ACID的"持久性"部分,但您可能并不在意)。
1.您可以使用journal_size_limit杂注控制磁盘上WAL文件的大小(如果您不方便的话)。您也可以更频繁地手动检查点。请参阅此处的"避免过大的WAL文件":https://www.sqlite.org/wal.html
1.我不喜欢所有对WAL模式的迷信抨击,WAL模式更快,更并发,而且简单得多,因为它省去了所有的锁定级别诡计(以及大多数"数据库忙"问题)与回滚日志一起出现。WAL模式几乎在每种情况下都是正确的选择。(唯一有问题的地方是在不支持共享内存Map访问文件的flash文件系统上。"非官方的" SQLITE_SHM_DIRECTORY编译指令可用于将. shm文件移动到不同类型的文件系统--例如tmpfs--但这在iOS上不应成为问题。)
qoefvg9y2#
我很困惑,这里有多少人建议删除WAL文件是安全的,甚至没有人朝他们的方向看。
The documentation明确将此列为破坏数据库的正式方式之一。它没有说删除热WAL可能会导致您丢失最近的事务或类似的良性操作。它说它可能会破坏数据库。
为什么?因为应用程序可能在执行检查点操作的过程中崩溃。当发生这种情况时,数据库文件本身处于无效状态,除非与WAL中包含的新数据配对。
因此,答案是明确的否。不要删除WAL文件。
要清除该文件,可以调用
PRAGMA schema.wal_checkpoint(TRUNCATE);
jaxagkaj3#
我在iOS 7中看到了不少关于WAL的负面报道。我不得不在几个项目上禁用它,直到我有时间更彻底地探讨这些问题。
我不会删除日志文件,但您可以使用清空SQLite文件的选项,这将导致SQLite“消耗”日志文件。您可以在将
NSPersistentStore
添加到NSPersistentStoreCoordinator
时将NSSQLiteManualVacuumOption
作为选项的一部分添加来实现这一点。如果这最终是耗时的,那么我会建议禁用WAL。我还没有看到任何不良影响禁用它(尚未)。
wwwo4jvm4#
WAL模式有问题,不要使用它。问题各不相同,但你的报告非常大是一个,其他问题包括迁移过程中的失败(使用NSPersistentStoreCoordinators migratePersistentStore)和导入iCloud交易日志过程中的失败。因此,虽然有报告的好处,直到这些错误被修复,它可能是不明智的使用WAL模式。
不,你不能删除提前写日志,因为它包含最新的数据。
将数据库设置为使用回滚日志模式,我想您会发现在加载大量数据时不再需要这些非常大的文件。
这里有一个摘录解释了WAL是如何工作的。除非你能保证你的应用运行了一个检查点,否则我不知道你如何删除WAL文件而不冒删除已提交事务的风险。
WAL的工作原理
传统的回退日志的工作方式是将原始未更改数据库内容的副本写入单独的回退日志文件,然后将更改直接写入数据库文件。在崩溃或ROLLBACK事件中,回退日志中包含的原始内容将回放到数据库文件中,以将数据库文件还原到其原始状态。删除回退日志时会发生COMMIT。
WAL方法与此相反。原始内容保留在数据库文件中,更改附加到单独的WAL文件中。当指示提交的特殊记录附加到WAL时,COMMIT发生。因此,COMMIT可以在不写入原始数据库的情况下发生。这允许读取器在将更改同时提交到WAL的同时继续从原始未更改的数据库进行操作。多个事务可以附加到单个WAL文件的末尾。
检查点
当然,人们希望最终将追加到WAL文件中的所有事务传输回原始数据库,将WAL文件事务移回数据库称为“检查点”。
考虑回滚日志和预写日志之间差异的另一种方式是,在回滚日志方法中,有两个基本操作:阅读和写,而对于预写日志,现在有三个基本操作:阅读、写入和检查点。
默认情况下,当WAL文件达到1000页的阈值大小时,SQLite会自动执行检查点操作。(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT编译时选项可用于指定不同的缺省值。)使用WAL的应用程序不必执行任何操作就可以使这些检查点发生。但是如果它们希望这样做,应用程序可以调整自动检查点阈值。2或者,它们可以关闭自动检查点并在空闲时间或在单独的线程或进程中运行检查点。
rur96b6h5#
有相当好的答案在这个线程,但我添加这一个链接到苹果官方问答有关日志模式在iOS7核心数据:https://developer.apple.com/library/ios/qa/qa1809/_index.html
他们给予了不同的解决方案:
要安全地备份和恢复Core Data SQLite存储,您可以执行以下操作:
使用NSPersistentStoreCoordinator类的以下方法(而不是文件系统API)备份和还原核心数据存储:
请注意,这是我们推荐的选项。
如果必须复制存储文件,则在将存储添加到持久存储协调器时更改为回滚日志记录模式。清单1是显示如何执行此操作的代码:
清单1在添加持久存储时使用回滚日志记录模式
对于使用WAL模式加载的存储,如果主存储文件和对应的-wal文件都存在,则使用回滚日记模式将存储添加到持久性存储协调器将强制Core Data执行检查点操作,该操作将-wal文件中的数据合并到存储文件。这实际上是Core Data执行检查点操作的方式。另一方面,如果-wal文件不存在,则使用这种方法添加存储不会导致任何异常,但是记录在缺失的-wal文件中的事务将丢失。
非常重要的编辑内容
如果您的一些用户在
iOS 8.1
上,并且您选择了第一个解决方案(Apple推荐的解决方案),请注意,在整个迁移的数据库中,他们的many-to-many
数据关系将被完全丢弃、丢失、删除。这是
iOS 8.2
中修复的一个严重错误。更多信息请点击http://mjtsai.com/blog/2014/11/22/core-data-relationships-data-loss-bug/xpcnnkqh6#
永远不要删除sqlite WAL文件,因为它包含的事务还没有写入到实际的sqlite文件中,而是强制数据库进行检查点操作,然后为您清理WAL文件。
在CoreData中,最好的方法是使用DELETE日志模式杂注打开数据库,这将检查点,然后删除WAL文件。
出于理智的考虑,您应该确保在执行此操作时只有一个到持久性存储的连接,即在单个持久性存储协调器中只有一个持久性存储示例。
FWIW在您的特定情况下,您可能希望使用TRUNCATE或OFF进行初始数据库导入,并切换到WAL进行更新。
https://www.sqlite.org/pragma.html#pragma_journal_mode