Sqlite或核心数据来更新超过50000条logging

我正在为我的项目使用coredata。 但是,当API返回应用程序需要更新的54000个对象时,用户需要等待将近2个小时。 这是当前项目的主要问题,我正在考虑使用sqlite而不再使用coredata来更新数千个对象。

使用Sqlite是正确的决定还是有CoreData的build议? 我不能决定。 任何帮助将是伟大的。 谢谢。

这是我在做什么:

NSManagedObjectContext *privateObjectContext = [AppDelegate appDelegate].privateManagedObjectContext; [privateObjectContext performBlock:^{ int i = 1; for (NSDictionary *item in itemlist) { i++; [fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"itemID == %@",[item objectForKey:@"item_id"] ]]; NSError *error; NSMutableArray *inventories = [[NSMutableArray alloc]initWithArray: [privateObjectContext executeFetchRequest:fetchRequest error:&error]]; ItemManagedObject *itemMO; if(inventories.count){ itemMO = inventories.firstObject; }else{ itemMO = [NSEntityDescription insertNewObjectForEntityForName:@"ItemObject" inManagedObjectContext:privateObjectContext]; } [itemMO prepareWithDictionary:item]; } NSError *error; if (![privateObjectContext save:&error]) { completionHandler(NO); } } 

2个小时很长。 这很奇怪。

然而,你可以通过让核心数据做更less的工作来按摩你的代码。 更less的工作。

  1. 执行单个提取请求而不是54K提取请求
  2. 当一个属性值没有改变时不要调用一个托pipe对象属性设置器 ,这样就不会有不必要的标记为脏的对象,并且当“save”方法是“核心数据”时,核心数据不必执行代价高昂但无用的更新调用。

这将显着减lessCore Data所执行的工作量,以及您的应用程序的性能。

第二点很简单,但非常冗长:在调用setter之前,比较每个单独的属性值和字典值。

第一点需要改变algorithm:

执行单个提取请求,按idsorting([NSFetchRequest setSortDescriptors:])

按idsorting字典([NSArray sortedArray …])

同步两个sorting的列表(两个列表sorting是最重要的):

 NSEnumerator *itemMOEnum = [itemMOs objectEnumerator]; NSEnumerator *dicEnum = [dictionaries objectEnumerator]; ItemManagedObject *itemMO = [itemMOEnum nextObject]; NSDictionary *itemDic = [dicEnum nextObject]; while (itemDic) { NSComparisonResult comparison = itemMO ? [itemDic[@"item_id"] compare:itemMO.itemID] : NSOrderedAscending; switch (comparison) { case NSOrderedSame: // id present in both lists: update [itemMO prepareWithDictionary:itemDic]; itemMO = [itemMOEnum nextObject]; itemDic = [dicEnum nextObject]; break; case NSOrderedAscending: { // id present only in dictionaries: create itemMO = [NSEntityDescription insertNewObjectForEntityForName:@"ItemObject" inManagedObjectContext:privateObjectContext]; [itemMO prepareWithDictionary:itemDic]; itemDic = [dicEnum nextObject]; } break; case NSOrderedDescending: // id present only in managed object: delete or do nothing itemMO = [itemMOEnum nextObject]; break; } } while (itemMO) { // id present only in managed object: delete or do nothing itemMO = [itemMOEnum nextObject]; } 

并保存。

最后,也许SQLite会更快(请参阅https://github.com/groue/GRDB.swift/wiki/Performance,以便比较Core Data与SQLite库的性能)。

但是SQLite不会把慢速algorithm变成一个快速的algorithm

核心数据提供NSBatchUpdateRequest ,它允许您直接在持久性存储上进行更新,而不涉及在内存中实例化和处理pipe理对象。

您应该使用核心数据性能工具来运行此代码。 如果itemList包含54,000个对象,那么您将对持久性存储执行54,000次提取,以便每次检查一个ID。 要提前获取所有ID,然后检查内存中的结果要比执行重复的提取请求要快得多 – 原始SQL中的代码几乎与核心数据中的代码一样慢。

此代码也看起来不正确:

 ItemManagedObject *itemMO; if(itemMO.count){ 

如果testing,除非你错过了某一行,否则永远不会通过。

我从来没有在sqlite中重做核心数据项目,反之亦然。 所以我不能告诉你是否有性能差异/

但54k = 2小时的事情听起来很奇怪。 你谈论一个API,这让我怀疑涉及服务器,你的问题是关于数据库。 当然,2小时听起来太长了,让我怀疑你的数据库的核心devise是否有问题。 例如缺乏索引。 根据您的查询和数据库,单个更新可能会触发各种重型处理。

另一个是你为什么要在设备上处理这一列的数据。 这是很多要处理,我不知道是否有办法减less音量下降,有select地做更新甚至更好 – 将其移动到服务器。

我想你需要重新思考你的问题。 提供关于数据库的更多上下文,正是你在做什么以及为什么。

CoreData不是一个数据库pipe理器,而是一个对象图和持久性pipe理器。 CoreData可以将其对象存储在sqlite数据库中,也可以存储在XML文件或二进制文件中(开发人员可以select最适合其需求的选项)。

CoreData和数据库pipe理器的主要区别在于,要访问CoreData对象,CoreData需要实例化Objective-C / Swift对应的对象。

Sqlite可以访问部分数据,而不必提取包含数据的完整logging。

然后,CoreData需要维护对象之间的关系图(2个CoreData类之间的关系,并且一般来说都是这两种关系)。

因此,当更新54k对象时,您要求CoreData实例化54k对象(在内存中)并最终更新它们的关系。

对于移动CoreData来说这是非常繁重的工作。

也许你的CoreData模型没有被正确的优化。 也许你应该定期保存CoreData上下文,并刷新CoreData暂存器(包含实际读取或更新对象的内存部分)。

但是根据我的经验,CoreData不适合繁重的数据工作。

用sqlite重新实现你的需求可能是一些工作,如果你想能够从sqlitelogging重新实例化你的类对象,并pipe理相当自动的关系,但它是可行的。 我做了一些项目。 这增加了一个模型对象的好处,因为sqlite在很多平台上都可用,所以比如像Android这样的其他平台可以共享更多的模型对象。

还有一件事:sqlite更适合从多个线程使用。 CoreData对此更加敏感,并且需要一个线程的上下文,最终还有一些上下文同步。