在Core Data中执行批量INSERT / UPDATE / DELETE的有效方法。

时间:2013-11-27 17:48:58

标签: ios iphone core-data ios6

我有一个包含200,000个项目的JSON对象。我需要迭代这些对象,并确定它们是否存在并执行相关操作(插入/更新/删除)。这个shell如下所示。当然,它实际上并没有保存任何东西。更多的是看这种方式需要多长时间。考虑到甚至还没有发生任何变化,这个动作在iPhone 4上处理大约需要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];

                                             }

                                         });


                       }];


                   });
}

3 个答案:

答案 0 :(得分:6)

看一看 “核心数据编程指南”中的Implementing Find-or-Create Efficiently

更新:在当前的核心数据编程指南中不再存在本章。可以在以下位置找到存档版本 http://web.archive.org/web/20150908024050/https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html。)

其中一个关键想法是不对每个产品执行一次获取请求,而是执行一次 使用类似

的谓词进行“批量提取”
[NSPredicate predicateWithFormat:@"code IN %@", productCodes]

其中productCodes是来自JSON数据的“很多”产品代码数组。 当然,您必须找到最佳的“批量大小”。

答案 1 :(得分:1)

有了这么多的对象,我认为你需要开始非常聪明地研究你的数据和系统,并在获取200K JSON对象之前寻找其他方法来修剪你的项目。您说您使用的是Core Data并且在iPhone上,但是您没有指定这是否是客户端/服务器应用程序(从手机上攻击Web服务器)。我会尽力保持我的建议。

实际上,您应该考虑当前的JSON以外的其他数据/元数据,这些数据/元数据可以提供有关在合并/更新之前您真正需要获取的内容的提示。听起来你正在同步两个数据库(手机和遥控器)并使用JSON作为传输方式。

  1. 您可以为数据添加时间戳吗?如果您知道上次更新手机数据库,则只需在此之后提取更改的数据。
  2. 您可以在部分/分区中发送数据吗? 1000-10000的分组可能更易于管理。
  3. 您可以将数据划分为与用户/应用程序或多或少相关的部分吗?通过这种方式,首先更新用户首先触摸的项目。
  4. 如果您的数据是地理位置,您是否可以先将数据发送到感兴趣的区域?
  5. 如果您的数据是产品,您可以先发送用户最近查看过的数据吗?
  6. 如果您的数据是分层的,您可以将根节点标记为已更改(或再次标记时间戳)并仅更新已更改的子树吗?
  7. 我会在任何系统中犹豫不决,无论是网络数据库还是本地数据库,都试图合并200K项目列表中的更新,除非它是一个非常简单的列表(如数字合并排序)。这是浪费大量时间和网络资源,并不会让您的客户感到非常高兴。

答案 2 :(得分:0)

不要处理单个项目,批处理它们。目前,您对上下文进行了大量的获取请求,这些需要花费时间(使用Core Data Instruments工具来查看)。如果您最初将处理的批处理大小设置为100,则获取该组ID,然后在fetch results数组中本地检查是否存在。