删除sqlite的WAL文件是否安全?

时间:2014-01-07 11:05:08

标签: ios core-data sqlite

我在iOS应用中遇到一个奇怪的问题,有时WAL文件会变成巨大的(~1GB)。看来还有其他人有问题(例如Core Data sqlite-wal file gets MASSIVE (>7GB) when inserting ~5000 rows)。

我最初的想法是在应用启动时删除WAL文件。从阅读关于此事的sqlite文档来看,这似乎没问题。但有人知道这样做的任何缺点吗?

我当然喜欢深入了解为什么WAL文件增长如此之大,但我现在无法找到它的底部,并希望在我的时候进行解决方法深入研究问题。

值得指出的是,我的核心数据数据库更像是一个缓存。因此,如果我丢失了WAL中的数据并不重要。我真正需要知道的是,如果删除WAL,数据库是否会完全损坏?我的怀疑是否定的,否则WAL并没有达到其目的之一。

6 个答案:

答案 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)

一些事情:

  1. 您当然可以删除WAL文件。您将丢失尚未检查点回主文件的任何已提交事务。 (因此违反了ACID的“耐久性”部分,但也许你不在乎。)

  2. 您可以使用journal_size_limit编译指示控制磁盘上WAL文件的大小(如果它困扰您)。您可能还需要更频繁地手动检查点。请参阅此处的“避免过大的WAL文件”:https://www.sqlite.org/wal.html

  3. 我不喜欢所有迷恋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以进行更新。

http://www.sqlite.org/pragma.html#pragma_journal_mode