【问题标题】:Core Data slow fetching relationship objectsCore Data 缓慢获取关系对象
【发布时间】:2018-09-06 06:26:24
【问题描述】:

我正在从 Core Data 加载所有 Node 实体,获取请求如下:

NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Node"];
self.graphNodes = [self.viewController.objectContext executeFetchRequest:request error:&error];

实体NodeDeparture 实体具有一对多有序 (NSOrderedSet) 关系。我直接与他们合作:

self.nodeDepartures = node.departures.array;
Departure* departure = self.nodeDeparturesReference[index]; //Slow operation

但是最后一个操作执行得很慢,我不明白为什么。在 XCode 的时间分析器中,我看到很多 NSSQLCore 方法的执行。这是一个被调用方法的image,但主要的是(按时间顺序):

[_NSFaultingMutableOrderedSet objectAtIndex:]
[_NSFaultingMutableOrderedSet willReadWithContents:]
[NSFaultHandler retainedFulfillAggregateFaultForObject:andRelationship:withContext:]
[NSPersistentStoreCoordinator(_NSInternalMethods) newValueForRelationship:forObjectWithID:withContext:error:]
... and cca. 20 more strange calls (check the image) ...

据我所知,发生了一些错误,程序找不到所需的数据。我究竟做错了什么?请有任何想法。

编辑 1: 我发现问题在于错误关系(更多关于错误here)。问题已通过获取节点的新方法“解决”:

NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Node"];
[request setReturnsObjectsAsFaults:NO];
[request setRelationshipKeyPathsForPrefetching:@[ @"departures" ]];
self.graphNodes = [self.viewController.objectContext executeFetchRequest:request error:&error];

无论如何,这对我来说不是一个好的解决方案,因为这种预取需要很多时间,但我需要立即使用Nodes 数组。有没有办法在后台线程中预取departures属性并并行使用数组?

【问题讨论】:

  • 您可以尝试在您的构建方案中将-com.apple.CoreData.SQLDebug 1 添加到“启动时传递的参数” - 这将导致控制台记录核心数据正在执行的 SQL 查询,并且可能会深入了解什么是出错了
  • 出于兴趣,如果关系是无序的会更快吗?你可以使用无序对象,然后在内存中排序吗?
  • 您的 Departure 架构中是否有一些“重”对象会导致获取时间变慢(图像、blob > 1 Mo)?
  • 这个有序关系中大概有多少个对象?
  • 感谢您的回复。 @pbasdf 不幸的是,我需要对这些实体进行排序。 @FlorianBurel 在出发实体中,我有 1x String、2x Integer 16、3x Date 和 4x 一对一关系。 @TomHarrington 我总共有 ~1'500'000 次出发(每节点约 1`000)。

标签: ios objective-c xcode core-data


【解决方案1】:

您走在正确的轨道上,但每个节点有 1000 个左右的关系,您需要走得更远。

托管对象上下文维护所获取对象的内部缓存。您可能需要在需要它们之前通过提前获取对象来尝试“预热”缓存。尽早获取它们,但不要使用它们。稍后当您需要它们时,再次获取它们,结果将来自缓存。

初始获取不需要请求完整的对象。您可以将resultType 设置为managedObjectIDResultType 并获得相同的结果。

如果您使用后台队列(即不使用主队列的队列),这将最有效。在您需要结果之前,告诉后台队列在后台执行此提取,然后不要使用结果。

【讨论】:

  • 感谢您的回答。我试图这样做,但无论如何它太慢了。现在我正在尝试使用另一个名为NSData 的数据结构。我在应用程序的开头加载它,如下所示:Structure* database = [NSKeyedUnarchiver unarchiveObjectWithData:my_data]; 其中my_data 是来自导入文件的数据。不幸的是,它甚至比 sql 方法还要慢。你知道有什么方法可以快速从文件中加载所需的数据吗?也许,我可以创建类似“内存转储”的内容并在不取消归档的情况下加载它吗?
  • 我想知道的是,您是否真的需要所有 ~1000 个相关对象同时,或者您是否可以使用一种不同的方法而不是一次获得所有对象. Core Data 的主要优势之一是可以只加载数据的一部分而不是全部。
  • 我需要所有相关的对象,因为应用程序依赖于用户的输入数据。输入之前不知道用户的输入,但是输入的时候一定要尽快显示结果。
  • 我的意思是,当你得到这 1000 个对象时,你在做什么?一次在屏幕上显示所有这些?基于它们进行某种计算?可能有一种更好的方法,不需要一次将所有这些都存储在内存中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多