Ios 在CoreData中执行批量插入/更新/删除的有效方法。

Ios 在CoreData中执行批量插入/更新/删除的有效方法。,ios,iphone,core-data,ios6,Ios,Iphone,Core Data,Ios6,我有一个JSON对象,包含200000项。我需要遍历这些对象,确定它们是否存在,并执行相关操作(插入/更新/删除)。用于此操作的外壳如下所示。当然,它实际上还没有保存任何东西。更重要的是看这条路需要多长时间。在iPhone4上处理这个动作大约需要8分钟,考虑到还没有发生任何变化,这看起来很疯狂 有没有更有效的方法来处理这个问题 如有任何建议或建议,将不胜感激 - (void) progressiveInsert { prodAdd = 0; prodUpdate = 0;

我有一个JSON对象,包含200000项。我需要遍历这些对象,确定它们是否存在,并执行相关操作(插入/更新/删除)。用于此操作的外壳如下所示。当然,它实际上还没有保存任何东西。更重要的是看这条路需要多长时间。在iPhone4上处理这个动作大约需要8分钟,考虑到还没有发生任何变化,这看起来很疯狂

有没有更有效的方法来处理这个问题

如有任何建议或建议,将不胜感激

- (void) progressiveInsert
{
    prodAdd = 0;
    prodUpdate = 0;
    prodDelete = 0;

    dispatch_queue_t backgroundDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

    dispatch_async(backgroundDispatchQueue,
                   ^{
                       _productDBCount = 0;

                       NSLog(@"Background Queue");
                       NSLog(@"Number of products in jsonArray: %lu", (unsigned long)[_products count]);

                       NSManagedObjectContext *backgroundThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
                       [backgroundThreadContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
                       [backgroundThreadContext setUndoManager:nil];

                       [fetchRequest setPredicate:predicate];
                       [fetchRequest setEntity:[NSEntityDescription entityForName:@"Products" inManagedObjectContext:_managedObjectContext]];
                       [fetchRequest setIncludesSubentities:NO]; //Omit subentities. Default is YES (i.e. include subentities)
                       [fetchRequest setFetchLimit:1];

                       [_products enumerateObjectsUsingBlock:^(id product, NSUInteger idx, BOOL *stop) {

                           predicate = [NSPredicate predicateWithFormat:@"code == %@", [product valueForKey:@"product_code"]];
                           [fetchRequest setPredicate:predicate];

                           NSError *err;
                           NSArray *fetchedObjects = [_managedObjectContext executeFetchRequest:fetchRequest error:&err];

                           if (fetchedObjects == nil) {

                               if ([[product valueForKey:@"delete"] isEqualToNumber:[NSNumber numberWithBool:TRUE]]){
                                   prodDelete += 1;
                               } else {
                                   prodAdd += 1;
                               }

                           } else {

                               if ([[product valueForKey:@"delete"] isEqualToNumber:[NSNumber numberWithBool:TRUE]]){
                                   prodDelete += 1;
                               } else {
                                   prodUpdate += 1;
                               }

                           }

                           dispatch_sync(dispatch_get_main_queue(), ^
                                         {

                                             self.productDBCount += 1;
                                             float progress = ((float)self.productDBCount / (float)self.totalCount);
                                             _downloadProgress.progress = progress;

                                             if (_productDBCount == _totalCount){
                                                 NSLog(@"Finished processing");
                                                 _endProcessing = [NSDate date];
                                                 [_btn.titleLabel setText:@"Finish"];
                                                 NSLog(@"Processing time: %f", [_endProcessing timeIntervalSinceDate:_startProcessing]);
                                                 NSLog(@"Update: %i // Add: %i // Delete: %i", prodUpdate, prodAdd, prodDelete);
                                                 [self completeUpdateProcess];

                                             }

                                         });


                       }];


                   });
}
看看 在“核心数据编程指南”中

(更新:本章不再存在于当前的核心数据编程指南中。存档版本可在 )

其中一个关键思想不是对每个产品执行一个获取请求,而是执行一个 带有类似谓词的“批量获取”

[NSPredicate predicateWithFormat:@"code IN %@", productCodes]
其中,
productCodes
是JSON数据中“许多”产品代码的数组。
当然,您必须找到最佳的“批量大小”。

不要处理单个项目,而是批量处理它们。目前,您向上下文发出大量的获取请求,这些请求需要时间(请使用核心数据工具工具查看)。如果您最初将处理的批处理大小设置为100,然后获取该组ID,然后在本地检查获取结果数组中是否存在。

对于这么多的对象,我认为您需要开始非常巧妙地处理数据和系统,并在获取200K JSON对象之前寻找其他方法来修剪项目。你说你正在使用核心数据,并且在iPhone上,但你没有指定这是否是一个客户机/服务器应用程序(从电话中点击web服务器)。我会尽量把我的建议概括起来

实际上,您应该跳出当前的JSON,更多地考虑其他数据/元数据,这些数据/元数据可以为您在合并/更新之前真正需要获取什么提供提示。听起来您正在同步两个数据库(电话和远程),并使用JSON作为传输手段

  • 你能给你的数据加时间戳吗?如果您知道上次更新手机数据库的时间,您只需提取该时间之后更改的数据
  • 您能以分区/分区的形式发送数据吗?1000-10000组可能更易于管理
  • 您能否将数据划分为与用户/应用程序或多或少相关的部分?这样,用户首先触摸的项目将首先更新
  • 如果您的数据是地理数据,您能否先将数据发送到感兴趣的区域附近
  • 如果您的数据是产品,您能否先发送用户最近查看的数据
  • 如果您的数据是分层的,您可以将根节点标记为已更改(或者再次标记为时间戳),并且只更新已更改的子树吗

  • 在任何系统中,无论是网络数据库还是本地数据库,我都会犹豫是否尝试合并来自200K项列表的更新,除非它是一个非常简单的列表(如数字合并排序)。这是对时间和网络资源的极大浪费,也不会让您的客户非常满意。

    啊,好的。这是有道理的。这是我应该在现有的“_产品”迭代中做的事情,还是以不同的方式?例如,将产品代码添加到数组中。然后,当数组计数达到X(100)时,它会执行批处理获取,然后执行CoreData操作(插入/更新/删除)。@LukeSmith:我认为没有标准的方法可以做到这一点。您所描述的是一种可能的解决方案。@Martin R,链接是broken@Bearwithme:核心数据编程指南现在位于此处:。它已被大量重写(见“文件修订历史”)。不幸的是,许多部分都被删除了,“高效地实现查找或创建”似乎就是其中之一。其目的是将这些记录的大部分包含在预填充的数据库中。然而,由于这些记录可能需要以大约1000/天的速度更新,如果有人每周更新一次以上,这将需要很长时间。理想情况下,任何人都不应该一次更新这么多项目,这只是一种预防措施。随后的更新将使用最后接收到的更新的ID进行请求(与时间戳建议的用途相同),以便只接收相关的更新。我有两个不同的更新路径。一个用于CD实体中没有记录的情况,它只是批量导入“当前”数据(不是更新,即数据集的最新完整版本)。在iPhone4上这大约需要4分钟。另一个是当存在记录时,它需要执行插入/更新/删除迭代(如本文所述)。Luke,即使你找到一种方法将CD更改速度提高10倍(我相信你会喜欢较小的更新),你仍然需要30-60秒才能完成200K。即使是1000/天,也就是7000/周或10秒,不加速。我一直在想你的系统设计。你的用例是什么?当网络可用或大部分断开连接且用户点击按钮更新数据时,是否经常使用该应用程序?是自动的吗?你真的需要手机上的每一个值都立即更新吗?谷歌可以在网上自动完成搜索词,你有什么迫切需要立即呈现所有内容?我不能给出任何细节。本质上,它是一个产品信息目录,通常在没有可用网络连接时使用。我们曾想过在需要时进行实时查找,但目前根本不可行。更新将由用户触发,最有可能的是某种形式的可配置通知频率,以确保定期更新。如果没有这些数据,这个应用程序基本上是无用的,而且如果某些信息丢失,也会引起法律上的关注。好吧,我想我们在如何帮助你方面已经到了极限——对不起。我写了一些CD的作品,但你有一个