我在iOS应用中遇到一个奇怪的问题,有时WAL文件会变成巨大的(~1GB)。看来还有其他人有问题(例如Core Data sqlite-wal file gets MASSIVE (>7GB) when inserting ~5000 rows)。
我最初的想法是在应用启动时删除WAL文件。从阅读关于此事的sqlite文档来看,这似乎没问题。但有人知道这样做的任何缺点吗?
我当然喜欢深入了解为什么WAL文件增长如此之大,但我现在无法找到它的底部,并希望在我的时候进行解决方法深入研究问题。
值得指出的是,我的核心数据数据库更像是一个缓存。因此,如果我丢失了WAL中的数据并不重要。我真正需要知道的是,如果删除WAL,数据库是否会完全损坏?我的怀疑是否定的,否则WAL并没有达到其目的之一。
答案 0 :(得分:9)
WAL模式有问题,请勿使用它。问题各不相同,但报告的大小非常大,其他问题包括迁移期间的故障(使用NSPersistentStoreCoordinators migratePersistentStore)和导入iCloud事务日志期间的故障。因此,虽然有报告的好处,直到这些错误得到修复,使用WAL模式可能是不明智的。
并且不能删除Write Ahead Log,因为它包含最新数据。
将数据库设置为使用回滚日志模式,我认为在加载大量数据时,您会发现不再拥有这些非常大的文件。
这是一个解释WAL如何工作的摘录。除非您可以保证您的应用程序运行了检查点,否则我不会看到如何删除WAL文件而不会冒被删除已提交事务的风险。
WAL如何工作
传统的回滚期刊的工作原理是写一份 原始未更改的数据库内容到单独的回滚日志中 文件,然后将更改直接写入数据库文件。在里面 崩溃事件或ROLLBACK,原始内容包含在 回滚日志将回放到数据库文件中以还原 数据库文件到其原始状态。 COMMIT发生在 回滚日志已删除。
WAL方法将此反转。原始内容保留在 数据库文件和更改将附加到单独的WAL中 文件。当指示提交的特殊记录时发生COMMIT 附加到WAL。因此,COMMIT可以在没有写入的情况下发生 原始数据库,允许读者继续操作 同时进行更改时原始未更改的数据库 致力于WAL。可以将多个事务追加到 单个WAL文件的结尾。
<强>点检查强>
当然,人们希望最终转移所有交易 在WAL文件中附加回原始数据库。移动 将WAL文件事务返回到数据库中称为a “检查点”。
另一种思考回滚和回滚之间差异的方法 预写日志是在rollback-journal方法中有的 两个原始操作,读写,而与 预写日志现在有三个原始操作:阅读, 写作和检查点。
默认情况下,SQLite会在WAL文件时自动执行检查点 达到1000页的阈值大小。 (该 可以使用SQLITE_DEFAULT_WAL_AUTOCHECKPOINT编译时选项 指定一个不同的默认值。)使用WAL的应用程序不必这样做 任何事情都是为了让这些检查站发生。但如果他们想要的话 到,应用程序可以调整自动检查点阈值。要么 他们可以在关闭期间关闭自动检查点并运行检查点 闲置时刻或单独的线程或过程。
答案 1 :(得分:7)
我在iOS 7中看到过很多关于WAL的负面报道。我必须在几个项目中禁用它,直到我有时间更全面地探讨这些问题。
我不会删除日志文件,但您可以使用清除SQLite文件的选项,这将导致SQLite“使用”日志文件。您可以在NSSQLiteManualVacuumOption
添加NSPersistentStore
时将NSPersistentStoreCoordinator
作为选项的一部分添加。
如果这最终耗费时间,那么我建议禁用WAL。我还没有看到任何禁用它的不良影响。(
)答案 2 :(得分:7)
一些事情:
您当然可以删除WAL文件。您将丢失尚未检查点回主文件的任何已提交事务。 (因此违反了ACID的“耐久性”部分,但也许你不在乎。)
您可以使用journal_size_limit编译指示控制磁盘上WAL文件的大小(如果它困扰您)。您可能还需要更频繁地手动检查点。请参阅此处的“避免过大的WAL文件”:https://www.sqlite.org/wal.html
我不喜欢所有迷恋WAL模式的抨击。 WAL模式更快,更并发,更简单,因为它省去了与回滚期刊一起使用的所有锁定级别的恶作剧(以及大多数“数据库忙”问题)。 WAL模式几乎适用于所有情况。 (唯一有问题的地方是不支持共享内存映射访问文件的flash文件系统。在这种情况下,“非官方”SQLITE_SHM_DIRECTORY编译指令可用于将.shm文件移动到不同类型的文件系统 - 例如tmpfs - 但这不应该是iOS上的问题。)
答案 3 :(得分:4)
这个帖子有很好的答案,但是我添加了这个链接到Apple官方QnA关于iOS7核心数据中的日记模式: https://developer.apple.com/library/ios/qa/qa1809/_index.html
他们提供不同的解决方案:
要安全地备份和还原Core Data SQLite存储,您可以执行此操作 以下内容:
请使用NSPersistentStoreCoordinator类的以下方法 比文件系统API,备份和还原Core Data存储:
- (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)error
请注意,这是我们推荐的选项。
将商店添加到a时,更改为回滚日记模式 持久性存储协调器,如果您必须复制存储文件。 清单1是显示如何执行此操作的代码:
清单1添加持久存储时使用回滚日记模式
NSDictionary *options = @{NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}}; if (! [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error])
{
// error handling.
}
对于加载了WAL模式的商店,如果主存储文件和 对应的-wal文件 存在,使用回滚日记模式将存储添加到持久性 商店协调员将强制Core Data执行检查点 操作,它将-wal文件中的数据合并到存储文件中。 这实际上是执行检查点操作的核心数据方式。 另一方面,如果-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/
答案 4 :(得分:1)
让我感到困惑的是,这里有多少人建议删除WAL文件是安全的,而且方向看起来也不差。
The documentation明确将其列为破坏数据库的官方方法之一。但这并不意味着删除热门WAL可能会导致您丢失最近的交易或类似的良性交易。它说它可能损坏数据库。
为什么?因为应用程序可能在检查点操作的中间崩溃了。发生这种情况时,除非与WAL中包含的新数据配对,否则数据库文件本身处于无效状态。
所以答案是明确的。 不要删除WAL文件。
清除文件的方法是调用PRAGMA schema.wal_checkpoint(TRUNCATE);
答案 5 :(得分:0)
你永远不应该删除sqlite WAL文件,它包含尚未写入实际sqlite文件的事务。而是强制数据库到检查点,然后为您清理WAL文件。
在CoreData中,执行此操作的最佳方法是使用DELETE日志模式pragma打开数据库。这将检查点,然后为您删除WAL文件。
NSDictionary *options = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"DELETE"}};
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:_storeURL
options:options
error:&localError];
为了完整起见,您应确保在执行此操作时只与持久性存储建立一个连接,即在单个持久性存储协调器中只有一个持久性存储实例。
FWIW在您的特定情况下,您可能希望使用TRUNCATE或OFF进行初始数据库导入,并切换到WAL以进行更新。