我有一个包含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];
}
});
}];
});
}
答案 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作为传输方式。
我会在任何系统中犹豫不决,无论是网络数据库还是本地数据库,都试图合并200K项目列表中的更新,除非它是一个非常简单的列表(如数字合并排序)。这是浪费大量时间和网络资源,并不会让您的客户感到非常高兴。
答案 2 :(得分:0)
不要处理单个项目,批处理它们。目前,您对上下文进行了大量的获取请求,这些需要花费时间(使用Core Data Instruments工具来查看)。如果您最初将处理的批处理大小设置为100,则获取该组ID,然后在fetch results数组中本地检查是否存在。