优化 NSFetchedResultsController 抓取

Posted

技术标签:

【中文标题】优化 NSFetchedResultsController 抓取【英文标题】:Optimize NSFetchedResultsController fetch 【发布时间】:2013-03-01 17:39:54 【问题描述】:

我有一个 NSFetchedResultsController 和存储在核心数据中的大量数据,获取的结果控制器必须获取这些数据。它最终将获取大约 46,000 件物品。问题是获取时间超过 8 秒,并且整个时间,UI 都被冻结,因为我们必须在主线程上获取。我想知道是否有什么办法可以加快速度?

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

由于用户可以搜索,因此 fetch 谓词会发生变化,因此在 fetched results 控制器上设置缓存似乎毫无意义,因为每次 fetch 谓词更改时它都会被删除。

它与 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];

【问题讨论】:

如果您可以添加 (a) 您的谓词和 (b) 您正在搜索的字段的类型(字符串、整数等),将会有所帮助。 您是否尝试为 fetch 谓词中使用的属性设置索引? 您通过“...其所有者的 UID”提及您的谓词过滤器。根据我的经验,关系会对获取性能产生很大影响。可能值得通过删除谓词的那部分来测试对速度的影响。 是的,fetch 谓词中使用的属性被索引了。我将立即使用代码编辑我的问题。 我在使用和不使用“ANY stories.permission.owner_person_uid”谓词的情况下对获取进行计时,大约需要 4 秒。对于 UI 无响应来说,这仍然太长了。肯定更好,但不幸的是,谓词是必要的。 【参考方案1】:

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

几件事可能会有所帮助:

在第三个谓词中,您正在查看@"(ANY stories.permission.owner_person_uid == %@ OR stories.@count == 0)"。谓词从左到右进行评估。数值比较比字符串比较快,所以先检查@count。如果为真,则无需评估后半部分,并且您将跳过大量字符串比较。 从左到右的顺序也适用于NSPredicate 实例的顺序。您可能对数据的外观有所了解 - 确保 限制性最强 谓词(即最大数量的对象将通过的谓词)是第一个列表中的一个。然后是第二个最严格的,等等。由于您将谓词和-ing 在一起,一个实例失败,第一个谓词将不需要与其他谓词进行检查。尽早过滤掉谓词链中的对象。

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

【讨论】:

【参考方案2】:

我想如果这对性能真的很重要的话,你总是可以稍微去规范化你的数据模型。您可以将 owner_person_uid 属性的副本添加到 stories 对象中。这样谓词就不必遍历这么多关系。

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

【讨论】:

以上是关于优化 NSFetchedResultsController 抓取的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 3 中难以配置 NSFetchedResultsController

如何根据计算的属性过滤来自 NSFetchedResultsController 的结果?

为啥 beginUpdates/endUpdates 会重置表视图位置以及如何阻止它这样做?

优化技巧汇总_通用优化+Linux 优化+HDFS 优化+MapReduce 优化+HBase 优化+内存优化+JVM 优化+Zookeeper 优化

优化技巧汇总_通用优化+Linux 优化+HDFS 优化+MapReduce 优化+HBase 优化+内存优化+JVM 优化+Zookeeper 优化

iOS性能优化总结