核心数据关系的性能改进
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 条记录块,请添加排序描述符并使用 fetchOffset
和 fetchLimit
。
获取记录的谓词是这样的。
NSArray *attributes = [e1Results valueForKeyPath:@"attributeInCommon"];
request.predicate =
[NSPredicate predicateWithFormat:@"attributeInCommon in @%", attributes];
我有两个核心数据实体(它们之间存在关系及其逆关系),它们已预先填充(每个实体大约有 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 条记录块,请添加排序描述符并使用 fetchOffset
和 fetchLimit
。
获取记录的谓词是这样的。
NSArray *attributes = [e1Results valueForKeyPath:@"attributeInCommon"];
request.predicate =
[NSPredicate predicateWithFormat:@"attributeInCommon in @%", attributes];