为啥 Core Data 插入需要越来越长的时间?

Posted

技术标签:

【中文标题】为啥 Core Data 插入需要越来越长的时间?【英文标题】:Why do Core Data inserts takes longer and longer?为什么 Core Data 插入需要越来越长的时间? 【发布时间】:2012-05-18 15:34:55 【问题描述】:

在我的 Core Data 应用程序中插入 2000 条记录时,我遇到了性能问题..

数据正在从服务器下载为一个大的JSON文件,并解析成一个JSON字典,这一切都很好,传递字典的时间也没什么……

问题是每次插入我的数据库需要的时间越来越长?

在导入过程中,我为每 100 个文档保存上下文以减少内存,第一个文档需要 0.005434 毫秒来保存,最后一个需要 0.039297 毫秒来保存..

我在一个单独的线程中执行所有这些导入,其中包含一个全新的 ManagedContext,其中 undomanager 设置为 nil..

这是遍历字典中所有文档的循环

    NSArray *docs = [docsData objectForKey:@"docs"];
    for(NSDictionary *doc in docs)
        if(counter++ % 100)
            [context save:nil];
        
        NSDate *start = [NSDate date];
        [Document documentWithDictionary:doc lastModifiedDate:[NSDate date] inLevels:nil inManagedObjectContext:context];
        NSDate *end = [NSDate date];

        NSLog(@"time used pr doc = %f",[end timeIntervalSinceDate:start]);
    
    [context save:nil];

这是插入文档的代码

     NSFetchRequest *req = [NSFetchRequest fetchRequestWithEntityName:@"Document"];
    req.predicate = [NSPredicate predicateWithFormat:@"id = %@", [data valueForKey:@"id"]];
    NSArray *matches = [context executeFetchRequest:req error:&error];

    if(matches)    
        if([matches count])
            document = [matches lastObject];
        else 
            document = [NSEntityDescription insertNewObjectForEntityForName:@"Document" inManagedObjectContext:context];
        
   

有人能解释一下为什么插入的时间越来越长吗?

在模拟器中,pr doc 的使用时间几乎是恒定的,但在手机上却不是?

这可能是一个小问题,但由于我可以在数据库中有 2000 到 30000 条记录,这实际上成为大量导入的一个因素..

非常感谢:)

/雅各布

更新-----

在数据库中只进行插入之后,即不获取现有记录,现在是时候了..

使用抓取:

1100 个文档 - 54.6 秒

2349 个文档 - 194.9 秒

1872 个文档 - 222.1 秒

无需获取。

1100 个文档 - 34.4 秒

2349 个文档 - 74.19 秒

1872 个文档 - 59.1 秒

因此,结论是我的 fetch 请求随着文档数量的增加而花费的时间越来越长.. 但这也是有道理的 :) 不知道为什么我之前没有想到这一点.. . 所以现在的解决方案是检查同步是否是第一个,然后在不获取任何现有文档的情况下导入文档。

/雅各布

【问题讨论】:

【参考方案1】:

根据您的代码,该问题与插入任何内容无关。在调用 save 方法之前,实际上没有任何东西会持久化到数据库中。我假设“...插入文档的代码”是 filesWithDictionary:lastModifiedDate:inLevels:inManagedObjectContext: 方法中的代码。您实际上并没有在此处插入任何内容,而是在内存中创建了一个新的 ManagedObject。但是,每次执行此操作时都在查询数据库。随着数据库中记录数量的增加,查询可能需要稍长的时间才能找到给定 id 的记录。

Apple 概述了一些有效导入大型数据集的良好做法:http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/coredata/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174-SW1

您尤其需要阅读“高效实施查找或创建”。按照他们的指导,您可以将数据库读取限制为每批记录一次,或者对您要导入的整个数据集只读取一次。

【讨论】:

是的,我知道我的代码在调用 save 之前不会插入任何内容,对不起,我在这里粘贴了错误的代码,正在使用的代码为 for 循环中的每 100 个文档保存。我实际上看过苹果文档,它们对我帮助很大,我会尝试实现查找或创建,但我还需要做“创建或更新”,所以如何以有效的方式做到这两个:) 我猜我可以在每次创建之前删除所有文档,但这似乎是在浪费时间 :) 感谢您的回复 只是让你知道,我刚刚更新了我的问题,并且我已经实现了查找或创建模式,现在它的性能都好很多,特别是第一个初始导入正在运行速度更快,应用程序使用时的小更新从来都不是问题.. 我很高兴它的表现好多了。至于更新现有记录,我倾向于使用 updateDate 并将其与我从我的服务中获得的内容进行比较。如果相同,我只是忽略记录并继续前进,否则我更新记录。但是,如果您无法从 Web 服务获取 updateDate 或哈希,您将只能更新不需要更新的记录。

以上是关于为啥 Core Data 插入需要越来越长的时间?的主要内容,如果未能解决你的问题,请参考以下文章

Myeclipse中tomcat启动时间越来越长?

iPhone:为啥 Core Data 中的 Bulk Inserts 这么慢?

上下文模式?为啥 Core Data 需要它?

为啥我需要 2 个或更多 Core Data 模型?

将 JSON 数据插入 Core Data 存储需要很长时间

使用 Core Data 插入/更新记录的最有效方法?