【问题标题】:Performance considerations on deleting Managed Objects using Cascade rule in Core Data在 Core Data 中使用 Cascade 规则删除托管对象的性能注意事项
【发布时间】:2012-04-28 14:00:52
【问题描述】:

我在 SO 中进行了搜索,但没有找到任何建议来提高在处理关系时删除 Core Data 中的托管对象的性能。

场景很简单。

如您所见,共有三个不同的实体。每个实体都与下一个实体级联。例如,FirstLevelSecondLevel 之间的关系称为 secondLevels。从FirstLevelSecondLevel 的删除规则是Cascade,而从SecondLevelFirstLevel 的删除规则是Nullify。在SecondLevelThirdLevel 之间应用相同的规则。

当我想删除整个图表时,我执行如下方法:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"FirstLevel" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSError *error = nil;
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];    

// delete roots object and let Core Data to do the rest...
for (NSManagedObject *managedObject in items) {
    [context deleteObject:managedObject];
}

利用 Cascade 规则删除图形。这对少数对象快速有效,但会降低许多对象的性能。另外,我认为(但我不太确定)这种类型的删除对磁盘执行了很多往返,我错了吗?

所以,我的问题如下:如何在不利用 Cascade 规则和提升性能的情况下删除图形,同时保持图形一致性?

提前谢谢你。

编辑

我无法删除整个文件,因为我的模型中有其他实体。

编辑 2

我发布的代码包含在NSOperation 子类的main 方法中。此解决方案允许在后台执行删除阶段。由于我利用了 Cascade Rule,因此删除是以半自动方式执行的。我只通过发布代码中的 for 循环删除根对象 FirstLevel 项。这样Core Data就为我做剩下的事情了。我想知道的是:是否可以绕过半自动删除操作并手动执行而不丢失图形一致性?

【问题讨论】:

  • 你想删除整个图表,我的意思是,清除所有持久存储,还是只清除一些分支?
  • 也许这对你有帮助?stackoverflow.com/questions/3266084/…
  • +1 为您的链接。问题是我无法删除整个文件,因为我的模型中有其他实体。我对我的问题添加了一个编辑。谢谢。

标签: ios performance core-data cascading-deletes object-relationships


【解决方案1】:

对于遍历和删除数据库中的对象所花费的时间,您无能为力。但是,您可以在后台执行此操作,这样 UI 就不会被阻塞。

例如,类似(代码假定为 ARC - 并且只是输入 - 未编译)...

- (void)deleteAllLevelsInMOC:(NSManagedObjectContext*)moc
{
    // Create a context with a private queue, so access happens on a separate thread.
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    // Insert this context into the current context hierarchy
    context.parentContext = context;
    // Execute the block on the queue of the context
    context.performBlock:^{
            NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"FirstLevel"];
            // This will not load any properties - just object id
            fetchRequest.includesPropertyValues = NO;
            // Iterate over all first-level objects, deleting each one
            [[context executeFetchRequest:fetchRequest error:0] 
                enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                [context deleteObject:obj];
            }];
            // Push the changes out of the context
            [context save:0];
    }];
}

请注意,您可以将 RootLevel 对象添加到您的数据模型中,并赋予它与第一级对象的一对多关系。然后,(只要你只有一个根对象)你所要做的就是删除那个根对象,它会删除 CoreData 中的所有其他内容。如果您有很多 FirstLevel 对象,那将是可行的方法。

或者,您可以将“新”上下文直接连接到持久存储,进行更改,并让其他上下文监视更改通知。

顺便说一句,如果您使用的是 UIManagedDocument,您可以免费获得这种背景,因为已经有一个父上下文在其自己的队列上运行,并且对主上下文的所有更改都传递给父上下文以实际执行数据库工作。

编辑

您可以手动执行,但您必须关闭级联规则。我发现我希望 CoreData 为我做尽可能多的事情。它减少了我的错误余地。

如果您已经在后台线程中删除,那么您如何看待性能问题?您必须在删除期间进行查询...这意味着您使用的是完成所有工作的 MOC。

您应该从 UIManagedDocument 中吸取教训。你应该有一个在私有队列上运行的 MOC。它完成了所有真正的工作。您有一个子 MOC,它只是将工作传递给该工作队列。

如果您实际上是在查询不在您要删除的图表中的对象,它们可能会被持久存储协调器的序列化属性挂起。如果是这种情况,您应该考虑单独的协调员,或者只有两个商店。

这样,您可以根据需要删除图表中的对象,同时仍响应对其他对象的请求。

【讨论】:

  • +1 感谢您的支持。我已经在后面的线程中删除了。您能否更好地解释一下您可以将“新”上下文直接连接到持久存储,进行更改,并让其他上下文监视更改通知 是什么意思?谢谢。
  • 也许发布您的整个删除代码然后... 至于第二部分,您可以创建多个使用相同 NSPersistentStoreCoordinator 的 MOC。但是,这将序列化对商店的访问...您还可以创建一个单独的 NSPersistentStoreCoordinator,然后您将可以并行访问商店...但是您还有其他问题需要处理。一般来说,最简单的解决方案总是最好的。
  • 感谢您的回复。创建多个 MOC 可能是一个有效的解决方案,但我需要一次执行该删除。请参阅我的第二次编辑。再次感谢您。
  • 我想知道你是否被propagatesDeletesAtEndOfEvent 击中。如果将其设置为 NO,它将在保存时进行所有传播。这是我没有使用过的一个属性,所以这是一个猜测。此外,请查看您的 KVO 和 Notification 客户端收到通知的频率。
【解决方案2】:

我通常使用-com.apple.CoreData.SQLDebug 1 打开 Core Data SQL 跟踪,如下所述:http://useyourloaf.com/blog/2010/3/11/debugging-core-data-on-the-iphone.html 这有助于检查 Core Data 是否符合我的预期。

您是否确保 [moc save:...] 需要这么长时间,而不是实际的 fetchrequest 来获取要删除的对象?如果是这种情况,您可以批量获取(然后删除)那些第一级对象。

【讨论】:

猜你喜欢
  • 2012-04-15
  • 1970-01-01
  • 2010-10-22
  • 2011-01-08
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多