核心数据 - 有效地查找或创建

时间:2013-10-15 23:05:11

标签: ios objective-c core-data optimization time

根据Apple的文档(link) -

  

在许多情况下,您可能需要查找现有对象   (已存储在商店中的对象)用于一组离散输入值。   一个简单的解决方案是创建一个循环,然后依次为每个值   执行提取以确定是否存在匹配的持久性   对象等。这种模式不能很好地扩展。如果你个人资料   使用此模式的应用程序,您通常会找到fetch   循环中较昂贵的操作之一(与之相比)   迭代一组项目)。更糟糕的是,这种模式转变了   O(n)问题导致O(n^2)问题。

     

在可能的情况下,更有效地创建所有托管   单个传递中的对象,然后修复一个中的任何关系   第二关。例如,如果导入您不知道的数据   包含任何重复项(例如,因为您的初始数据集为空),   您可以创建托管对象来表示您的数据,而不是   任何搜索都没有。或者,如果您导入“平面”数据,则无   关系,您可以为整个集创建托管对象   使用单个大IN保存之前清除(删除)任何重复项   谓词。

问题1:考虑到我导入的数据没有任何关系,我该如何实现最后一行中描述的内容。

  

如果您确实需要遵循查找或创建模式 - 请说明因为您   导入关系信息混合的异构数据   使用属性信息 - 您可以优化查找现有信息的方式   通过将执行的提取次数减少到最少来对象。   如何实现这一点取决于您的参考数据量   必须与之合作。如果要导入100个潜在的新对象,和   在您的数据库中只有2000,获取所有现有的和   缓存它们可能并不代表重大的惩罚(特别是如果   你必须多次执行操作)。但是,如果你   您的数据库中有100,000个项目,保持内存压力   那些缓存可能会让人望而却步。

     

您可以使用IN谓词和排序的组合来减少   您将Core Data用于单个提取请求。

示例代码:

// Get the names to parse in sorted order.
NSArray *employeeIDs = [[listOfIDsAsString componentsSeparatedByString:@"\n"]
        sortedArrayUsingSelector: @selector(compare:)];

// create the fetch request to get all Employees matching the IDs
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:
        [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:aMOC]];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat: @"(employeeID IN %@)", employeeIDs]];

// Make sure the results are sorted as well.
[fetchRequest setSortDescriptors:
    @[ [[NSSortDescriptor alloc] initWithKey: @"employeeID" ascending:YES] ]];
// Execute the fetch.
NSError *error;
NSArray *employeesMatchingNames = [aMOC executeFetchRequest:fetchRequest error:&error];
  

最终得到两个已排序的数组 - 一个传递了员工ID   到获取请求,以及与匹配的托管对象之一   他们。要处理它们,您可以按照这些列表查看已排序的列表   步骤进行:

     

获取下一个ID和员工。如果ID与员工ID不匹配,   为该ID创建一个新的Employee。获取下一个员工:如果是ID   匹配,移动到下一个ID和员工。

问题2:在上面的例子中,我得到了两个排序数组,如上所述。考虑到最坏的情况,即所有要插入的对象都存在于商店中,我无论如何都看不到我可以在O(n)时间内解决问题。 Apple描述了上述两个步骤,但这是一个O(n^2)工作。对于输入数组中的任何kth元素,可能存在或可能不存在与输出数组中的第一个k元素匹配的元素。因此,在最坏的情况下,复杂性将为O(nC2) = O(n^2)

所以,我认为Apple正在做的是确保即使需要进行O(n^2)检查,只获取一次进程。如果是这样,那么我会选择这个;但是有没有其他方法可以有效地做到这一点。

请理解,我不想一次又一次地获取 - 为一个大小为100的标识符的输入数组获取一次。

2 个答案:

答案 0 :(得分:3)

广告。 1 在这里建立关系的事实并不重要。此解释仅说明如果您从例如远程服务器和您的项目有一些ID,然后您可以在一个请求中从持久性存储中获取所有ID,而不是在单独的请求中获取每个对象。

广告。 2

  

Apple描述了上述两个步骤,但这是一个O(n ^ 2)工作。

不是。请仔细阅读以下几行:

  

要处理它们,请按照以下步骤操作已排序的列表:

     

获取下一个ID和员工。如果ID与员工ID不匹配,   为该ID创建一个新的Employee。获取下一个员工:如果是ID   匹配,移动到下一个ID和员工。

您同时遍历数组/列表,因此您无需进行此检查:“可能存在或可能不存在与输出数组中的前k个元素匹配的元素。”您不需要检查以前的元素,因为它们已经排序,它们肯定不会包含您感兴趣的对象。

答案 1 :(得分:0)