CoreData 性能:基于多对多关系

Posted

技术标签:

【中文标题】CoreData 性能:基于多对多关系【英文标题】:CoreData performance: predicate on more to-many relationships 【发布时间】:2011-10-25 21:31:29 【问题描述】:

使用 SQL 数据存储,我有一个这样的模型:

类别 > 项目

收藏 > 物品

品牌 > 商品

每个左侧实体与 Item 实体都有一个名为 items 的一对多关系。每一个都分别是 categorycollectionbrand 的一对一 Item 关系的倒数。

我想获取与特定集合和类别相关的至少一个项目的所有品牌对象。在自然语言中,我想要具有特定类别和特定系列的所有品牌的商品。

给定对象 Category *myCategoryCollection *myCollection,我用来在这样的品牌实体:

NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"(ANY items.category == %@) AND (ANY items.collection == %@)",myCategory,myCollection]; 

我得到了正确的结果。问题是性能。太慢了!我将问题简化为三个级别!让我们考虑 ios 多级目录中的四个级别:应用程序显示可用类别,用户选择一个类别,应用程序显示该类别中的集合,用户选择一个集合,应用程序显示该集合中的品牌(以及已选择的类别),用户选择一个品牌,应用程序会显示该品牌、系列和类别中的示例材料...

老实说,我使用 NSCompoundPredicate 在每次用户选择时放入 AND 子谓词,动态构建最终谓词。但这对于问题的目的无关紧要。

sql数据存储中Item实体的对象超过30,000(30k)个,items之间使用AND关系很慢(我注意到7-10在上面的示例中显示品牌的延迟秒数)。

我会尝试:

-从类别、收藏和品牌实体中删除 items 关系

-在项目实体上,将 categorycollectionbrand 关系替换为“category_id”、“collection_id”等属性上的获取属性和“brand_id”。

-使用 keypath 或谓词来获取品牌而不使用多对多关系。

在我开始破坏和重新制作过去6个月的整个作品之前,您有什么建议吗? :)

谢谢!

【问题讨论】:

【参考方案1】:

颠倒你正在寻找的逻辑。

您不是在寻找具有特定类别和特定系列的品牌;您正在寻找具有 X 类别和 Y 集合的 Item 实体。一旦您拥有该 Item,您就可以询问它的品牌:

id myCategory = ...;
id myCollection = ...;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Item"];
[request setPredicate:[NSPredicate predicateWithFormat:@"category == %@ && collection == %@", myCategory, myCollection]];

NSError *error = nil;
NSArray *itemArray = [moc executeFetchRequest:request error:&error];
NSAssert2(!error || itemArray, @"Error fetching items: %@\n%@", [error localizedDescription], [error userInfo]);

NSArray *brands = [itemArray valueForKey:@"brand"];
return brands;

更新

Item 是关系另一端的实体,就像您在问题中所拥有的一样。 -valueForKey: 将遍历项目数组并获取关系另一端的品牌实体,并返回品牌数组。您无需添加任何内容,甚至不需要添加属性,因为它将通过 KVC 访问并且“正常工作”。

这将根据您的要求为您提供最有效的检索。由于 Item 位于每个关系的多个方面,它将保存外键,因此 SQL 不需要跨越表边界,因此应该非常快。

唯一的其他选项,我不推荐它,但您可以使用来自 Category 和 Collection 的集合,并从可变集合中获取联合。每次我尝试这个方向时,它都会比访问数据库慢。在我看来,这种逻辑最好在数据库级别完成。

【讨论】:

当我阅读您的答案时,这就是我正在尝试的!这种逻辑效率更高,但我认为它仍然可以优化。考虑到:1)有超过 30k 个项目实体,获取请求需要一段时间,例如 1 秒而不是 7 秒使用多对关系,但仍然需要很长的用户体验等待时间(用户尝试“重复” ) 2) 当您使用 [itemArray valueForKey:@"brand"] 时,您如何在 Item 实体中为品牌建模?作为财产,关系或获取的财产?在第一种情况下,我需要另一个 n 获取请求...

以上是关于CoreData 性能:基于多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

CoreData 多对多关系插入和删除操作

保存循环删除多对多CoreData关系的一端

CoreData:使用 NSPredicate 过滤一对多对多关系(此处不允许错误对多键)

CoreData:如何建模循环多对多关系

CoreData:查询一对多对多的关系

CoreData :NSFetchedResultsController 一对多对多的关系