优化NSFetchedResultsController获取

时间:2013-03-01 17:39:54

标签: ios objective-c core-data

我有一个NSFetchedResultsController和存储在Core Data中的大量数据,读取的结果控制器必须提取这些数据。最终会有大约46,000件物品被拿走。问题是获取时间超过8秒,整个时间,UI被冻结,因为我们必须在主线程上获取。我想知道我能做些什么来加快这个速度吗?

我按照创建日期对对象进行排序,获取请求的批量大小为100,谓词不会过于复杂。它按照UID,类型和所有者的UID过滤对象。

由于用户可以进行搜索,因此获取谓词将会发生变化,因此每次获取谓词更改时,只需删除获取的结果控制器上的缓存就显得毫无意义。

它与Core Data中的对象数量直接相关,因为切换到具有较少对象的帐户会显着缩短获取时间。 (6000个物体不到一秒钟)。有没有办法让它更具可扩展性?我的代码如下:

- (NSFetchRequest *)getFetchRequest
{
    NSFetchRequest *fetchRequest = [NSFetchRequest requestWithEntityName:@"Photo"];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    [sortDescriptor release];
    [fetchRequest setPredicate:[self getFetchPredicates]];
    [fetchRequest setFetchBatchSize:100];
    return fetchRequest;
}

- (NSPredicate *)getFetchPredicates {
    NSMutableArray *predicates = [NSMutableArray arrayWithObjects:
                                  [NSPredicate predicateWithFormat:@"life_uid == %@",[[LoginManager shared] currentLifeUID]],
                                  [NSPredicate predicateWithFormat:@"(type == %@) OR (type == %@)", TLTypeImage, TLTypeVideo],
                                  [NSPredicate predicateWithFormat:@"(ANY stories.permission.owner_person_uid == %@ OR stories.@count == 0)", [[LoginManager shared] currentPersonUID]],
                                  nil];
    NSArray *filteredMomentIDs = [[self searchTerms] objectForKey:TLLibraryViewControllerSearchTermsPhotoIDsKey];
    if ([filteredMomentIDs count] > 0 && [self searchMode] == kTLLibrarySearchModeTag)
    {
        [predicates addObject:[NSPredicate predicateWithFormat:@"uid in %@", filteredIDs]];
    }
    return [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
}

2 个答案:

答案 0 :(得分:2)

由于您(在评论中)解释了所有属性都是字符串,因此您可能很难改善这种情况。你在fetch中做了很多的字符串比较 - 前两个谓词的46k记录乘以至少3,加上更多取决于平均有多少stories个关系。这是导致性能问题的主要原因 - 做很多字符串比较会成为瓶颈。

可能有所帮助的一些事情:

  • 在第三个谓词中,您正在查看@"(ANY stories.permission.owner_person_uid == %@ OR stories.@count == 0)"。谓词从左到右进行评估。数字比较比字符串比较更快,因此首先进行@count检查。如果这是真的那么下半部分将不需要进行评估,你将跳过大量的字符串比较。
  • 从左到右的事情也适用于NSPredicate个实例的顺序。您可能已经知道数据的样子 - 确保最严格的谓词(即最大数量的对象将通过的谓词)是第一个一个在列表中。然后是第二个最具限制性的,等等。由于你将谓词放在一起,一个实例失败,第一个谓词将不需要与其他谓词进行检查。尽可能早地在谓词链中过滤掉对象。

最简单的收益可能是通过更改第三个谓词中的顺序,然后将其移到列表的前面。

答案 1 :(得分:0)

我认为如果这对性能至关重要,您可以随时对数据模型进行去标准化。您可以将一个owner_person_uid属性的副本添加到stories对象中。这样,谓词就不必遍历如此多的关系。

如果您更改其中一个属性,此解决方案将要求您始终更新相关对象。