问题 插入~5000行时,Core Data sqlite-wal文件获得MASSIVE(> 7GB)


我正在将数据导入Core Data并发现保存操作很慢。使用iOS模拟器,我看到sqlite-wal文件增长并增长,直到它的大小超过7GB。

我正在导入大约10个字段的大约5000条记录。这不是很多数据。

我插入的每个对象与各种其他对象具有一对一的关系(总共6个关系)。所有这些记录合计不到20个字段。没有任何图像或任何二进制数据或任何我能看到的东西可以证明为什么WAL文件的结果大小如此巨大。

我阅读了描述wal文件的sqlite文档,但我不知道这是怎么发生的。源数据不超过50 MB。

我的应用程序是多线程的。 我在后台线程中创建一个托管对象上下文来执行导入(创建并保存核心数据对象)。

没有在这里编写代码,有没有人遇到过这个?任何人都想过我应该检查什么。代码不是非常简单,所有部分都需要时间在这里输入,所以让我们从一般的想法开始。

我会相信任何能让我朝着正确方向前进的人。

额外信息:

  • 我已经禁用了上下文的撤消管理器,因为我不需要它(我认为默认情况下它在iOS上是零,但我明确地将其设置为nil)。
  • 我只在整个循环完成后调用save并且所有托管对象都在ram中(ram上升到100 MB btw)。
  • 循环和创建核心数据对象只需要5秒左右。写入awl文件时保存大约需要3分钟。

12645
2017-11-26 21:38


起源

你会提供任何代码吗? - Shmidt
我会的,如果需要的话。但我真的在寻找创意。当我使用包装类和多个线程时,调用了很多代码。该行为似乎与sqlite子系统有关。我确定这是我正在做的事情。如果没有人遇到过这种情况,那么我会发布代码,也许我们可以看到导致这种情况的原因。 - Eric Risler
您是否尝试过打开核心数据SQL调试以查看实际执行的SQL是什么? - Jesse Rusak
如果您不使用WAL模式会发生什么? - Duncan Groenewald
SQL调试(在级别5)显示没有奇怪的SQL查询发生。我将测试限制在1000条记录中。 awl文件增长到877mb。 Xcode中的控制台输出86,231行文本(总大小为10.3mb)。 - Eric Risler


答案:


看来我的评论尝试使用旧的回滚(DELETE)日志模式而不是WAL日志模式修复了问题。请注意,使用WAL日志模式时似乎存在一系列问题,包括:

  • 这个问题
  • 使用migratePersistentStore API时数据库迁移的问题
  • 轻量级迁移的问题

也许我们应该启动Core Data WAL问题页面并获得一个全面的列表,并要求Apple修复这些错误。

请注意,OS X 10.9和iOS 7下的默认模式现在使用WAL模式。要更改此选项,请添加以下选项

@{ NSSQLitePragmaOptions : @{ @"journal_mode" : @"DELETE" } }

9
2017-11-27 20:39





事务的所有已更改页面都会附加到 -wal 文件。 如果要导入多个记录,则应该, 如果可能的话,使用单个事务进行整个导入。

SQLite不能完整 WAL检查站 而其他一些连接正在读取数据库(这可能只是你忘记关闭的一些声明)。


0
2017-11-26 21:54



你如何“忘记关闭”核心数据交易? - Mundi
我这样做我实际上已经禁用了上下文的撤消管理器,因为我不需要它(我认为默认情况下它在iOS上是零,但我明确地将其设置为nil)。我只在整个循环完成后调用save并且所有托管对象都在ram中(ram上升到100 MB btw)。循环和创建核心数据对象只需要5秒左右。写入awl文件时保存大约需要3分钟。 (将此添加到主要问题) - Eric Risler
好问题Mundi。我明白在sqlite世界中,如果你在数据库上打开了“Readers”(比如我正在读取db的其他线程),那么写入db文件的线程中的写入只会附加到WAL文件。这当然是有道理的 - 那不是WAL文件增长超过7GB。我正在检查sql调试输出。保持联系。 - Eric Risler
从SQLite网站:“但是,如果最后一个连接没有干净地关闭,WAL文件将保留在文件系统中,并在下次打开数据库时自动清理。”所以即使在sqlite设置“忘了关闭文件”这也是无稽之谈。 - Mundi
@Mundi可能的情况:单个应用程序启动事务但不关闭它:所有更改都发布到WAL,但由于事务未关闭,即既没有提交也没有回滚,WAL文件只是不断增长和增长。 - LS_ᴅᴇᴠ