核心数据关系的性能改进

Performance improvement in Core Data relationship

我有两个核心数据实体(它们之间存在关系及其逆关系),它们已预先填充(每个实体大约有 50k 个寄存器),我需要建立关系。这几乎是一个 1:1 关系。它们具有共同的属性,因此如果两个属性相等,则它们必须处于关系中。

我正在尝试以一种粗略的方式进行操作,并且遇到了很多内存问题(它很快升级为内存警告)。

@autoreleasepool {        
    NSFetchRequest *e2sRequest = [[NSFetchRequest alloc] initWithEntityName:@"Entity2"];
    e2sRequest.includesPropertyValues = NO;
    e2sRequest.includesSubentities = NO;
    NSArray *e2s = [self.fatherMOC executeFetchRequest:e2sRequest error:nil];

    if(e2s.count > 0) {
        NSFetchRequest *e1sRequest = [[NSFetchRequest alloc] initWithEntityName:@"Entity1"];
        e1sRequest.includesPropertyValues = NO;
        e1sRequest.includesSubentities = NO;
        NSArray *e1s = [self.fatherMOC executeFetchRequest:e1sRequest error:nil];

        for(Entity1 *e1 in e1s) {
            NSString *attributeInCommon = e1.attributeInCommon;
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"attributeInCommon = %@", attributeInCommon];
            Entity2 *e2matching = (Entity2 *)[e2s filteredArrayUsingPredicate:predicate].lastObject;
            if(e2) {
                e1.e2 = e2matching;
            }
        }
    }
}

我尝试在 NSDictionary 中获取公共属性和内存中的 objectID,但没有结果。我已经尝试了更多的方法,一些非常慢,而另一些则是可怕的记忆吞噬者。

我知道我必须检查错误,我知道我可以用更少的代码行来完成,但是把它看作是一个 debug/on 一个紧急代码,所以我会被修复。

提前致谢

您正在尝试同时加载 100000 个项目,因此您遇到内存问题也就不足为奇了。

你需要批处理,如果你创建了一个自动释放池,你有时需要耗尽它(所以它需要参与批处理)。

因此,在第一个提取请求上设置 fetchBatchSize。然后,遍历它发现的结果,一次取 fetchBatchSize 项。这是池应该在的地方,所以它在每批之后被释放。从一批 100 件开始,看看效果如何。

然后每个批次使用谓词进行第二个查询,以限制到可以与当前批次实际匹配的值集。

然后运行你的匹配逻辑。

还可以考虑使用 Instruments 中的核心数据工具来检查发生了什么,您向数据存储发出了多少请求以及这一切需要多长时间。

我想您不想在用户的设备上重复此操作(基于充当唯一键的公共字符串属性将 50.000 个实体与 50.000 个其他实体匹配)。相反,您似乎需要一次 来准备种子数据。

因此实际上不需要优化,因为时间和(在模拟器上)内存都不是问题。

所以只需分批执行此操作,例如如下:

  • 获取 1000 e1,
  • 用谓词获取1000个对应的e2
  • link
  • 保存
  • 耗尽内存
  • 重复

一些提示:

要获得不同的 1.000 条记录块,请添加排序描述符并使用 fetchOffsetfetchLimit

获取记录的谓词是这样的。

NSArray *attributes = [e1Results valueForKeyPath:@"attributeInCommon"];
request.predicate = 
    [NSPredicate predicateWithFormat:@"attributeInCommon in @%", attributes];