Sqlite或核心数据更新更多然后50000记录

问题描述:

我目前正在使用coredata为我的项目。但是,当API返回应用程序需要更新的54000个对象时,用户必须等待近2个小时。 这是当前项目的主要问题,我正在考虑使用sqlite而不再使用coredata来更新数千个对象。Sqlite或核心数据更新更多然后50000记录

使用Sqlite是否是正确的决定还是CoreData有任何建议?我无法决定。任何帮助都会很棒。谢谢。

下面是我在做什么:

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); 
     } 
} 
+0

你能描述一下你当前如何更新对象,这需要将近2个小时吗?可能有办法改进它,但是不可能说如果不知道你现在在做什么。 –

+0

是的,我们需要更多的细节,你如何处理更新,你多久保存一次上下文,你是否使用仪器来寻找瓶颈,发布一些代码 – trapper

+0

@TomHarrington我添加了代码。 – mega90

2小时很长。这很奇怪。

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

  1. 执行单一读取请求而不是54K提取请求
  2. 不要调用托管对象的属性设置当属性值不会改变,所以没有对象被不必要地标记为脏,并且在调用“保存”方法时,核心数据不必执行昂贵但无用的对象更新。

这将显着减少Core Data执行的工作量和应用程序的性能。

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

第一点需要一种算法变化:

执行单读取请求时,通过编号的顺序排列(与[NSFetchRequest setSortDescriptors:])

排序字典由ID(与[NSArray的sortedArray ...] )

同步两个排序列表(这是最重要的两个列表排序):

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对于试图在比较核心数据的使用SQLite库的性能)。

但SQLite的不会变成一个缓慢的算法成一快一

+0

谢谢soo。它需要7分钟。我从来没有想过使用NSEnumerator。抱歉迟了回应。 – mega90

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

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

另一种是你为什么要处理设备上的这一列数据。需要处理很多事情,我想知道是否有办法减少音量,选择性地进行更新,或者甚至更好 - 将其移动到服务器。

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

+0

就像@ jrturton说的那样:“如果itemList包含54,000个对象,那么您将对持久存储执行54,000次提取,以便每次检查一个ID。” 。我不知道这个coredata的工作系统。我想2小时的答案是这样的。 – mega90

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

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

Sqlite可以访问部分数据,而无需提取包含数据的完整记录。然后,CoreData需要维护对象之间的关系图(2个CoreData类之间的关系,并且通常以两种方式)。

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

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

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

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

如果你想能够从sqlite记录中重新实例化你的classe对象并管理相当自动的关系,但是它是可行的,那么用sqlite重新实现你的需求可能是一些工作。我在一些项目上做过。这增加了一个模型对象的好处,例如,可以在Android平台上与其他平台更加共享模型对象,因为sqlite在许多平台上都可用。

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

+0

感谢您的解释,现在我更好地理解核心数据和sqlite差异。有时候更好地询问并获得更多意见来理解问题并学习东西,然后在网上搜索并尝试获得一个想法(我搜索了,但现在我更好地理解了) – mega90

核心数据提供NSBatchUpdateRequest它允许你直接作出的持久性存储更新,而无需在内存中涉及实例和处理的管理对象。

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

此代码看起来也错了:

ItemManagedObject *itemMO; 

if(itemMO.count){ 

它永远不会通过,如果测试,除非你已经错过了线的地方。

+0

ups.while我编辑我的代码为*问题,我写错了。但每个3或4列可以有不同的值。非他们是一样的。所以NSBatchUpdateRequest对这种情况是没用的。但是,无论如何,谢谢。有了答案,我学到了更多关于sqlite coredata与更好解释之间的区别。因此,将结构转换为使用来自coredata的sqlite会很好。 – mega90