CoreData性能:取决于更多的关系 [英] CoreData performance: predicate on more to-many relationships

查看:118
本文介绍了CoreData性能:取决于更多的关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using SQL data store, I have a model like this:

类别<->>项目

Category <-->> Item

集合<->>项目

Collection <-->> Item

品牌<->>项目

Brand <-->> Item

每个左侧实体与Item实体之间有一个名为 items 的多对多关系.每个项目分别是一对一项目关系的倒数类别集合品牌.

Every left-side entity has a to-many relationship named items to the Item entity. Each one is the inverse of to-one Item relationships category, collection and brand respectively.

我想获取所有具有至少一个与特定收藏夹和类别有关的商品的品牌对象.用自然语言,我希望所有具有特定类别和特定收藏的商品品牌.

I want to fetch all Brand objects with at least one Item in relation with a particular Collection AND a Category. In natural language, I want all the brands of items with particular category and a particular collection.

鉴于对象 Category * myCategory Collection * myCollection ,我通常在这样的品牌实体:

Given the objects Category *myCategory and Collection *myCollection, I use to build a predicate on the Brand entity in this way:

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

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

And I get the correct results. The problem is performance. Too slow! And I simplified the question for three levels! Let's consider four levels in a iOS multilevel catalog: the app shows categories available, user select a category, the app shows collections in that category, user select a collection, the app shows brands in that collection (and the category already selected), user select a brand, the app shows for example materials in that brand,collection and category...

说实话,我在每个用户选择时都使用NSCompoundPredicate放入AND子谓词,动态地构建最终谓词.但这与问题的目的无关.

To be honest, i use NSCompoundPredicate to put in AND subpredicates at every user selection, building dynamically the final predicate. But this doesn't matter for the purpose of the question.

sql数据存储中有超过30,000(30k)个 Item 实体对象,并且在 items 关系之间使用AND非常慢(我注意到7-10在上面的示例中显示品牌所需的时间(秒).

There are more than 30,000 (30k) objects of Item entity in the sql data store, and using AND between items relationship is very slow (I noticed 7-10 seconds of lag to show brands in the example above).

我会尝试:

-从类别,集合和品牌实体中删除项目关系

-remove items relationships from Category, Collection and Brand entites

-在Item实体上,用获取的属性(如"category_id","collection_id")替换 category collection brand 关系和"brand_id".

-on the Item entity, replace category, collection and brand relationships with fetched properties on attributes like "category_id", "collection_id" and "brand_id".

-使用键路径或谓词来获取品牌,而无需使用多对多关系.

-use keypath or predicates to fetch the brands without using to-many relationships.

在我开始销毁并重新制作过去6个月的全部作品之前,您有什么建议吗? :)

Before I start to destroy and remake the whole work of the last 6 months, do you have any suggestion? :)

谢谢!

推荐答案

颠倒您要查找的逻辑.

Reverse the logic of what you are looking for.

您不是在寻找具有特定类别和特定收藏的品牌;您正在寻找具有X类别和Y集合的Item实体.拥有Item后,您可以询问其品牌:

You are not looking for a Brand with a certain category and a certain collection; you are looking for an Item entity that has a category of X and a collection of Y. Once you have the Item you can ask it for its brand:

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;

更新

项目是关系另一端的实体,就像您在问题中遇到的一样. -valueForKey:将遍历项目数组,并在关系的另一端获得Brand实体,并为您提供Brand数组.您不需要添加任何东西,甚至不需要添加属性,因为可以通过KVC访问它并且可以正常使用".

Update

Item is an entity on the other end of a relationship just as you have it in your question. -valueForKey: will go through the array of items and get the Brand entity on the other end of the relationship and give you back an array of the Brand. You do not need to add anything, not even a property since it will be accessed via KVC and will "just work".

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

This is going to give you the most efficient retrieval based on your requirement. Since Item is on the many side of each of those relationships it will hold the foreign keys and therefore the SQL will not need to cross table boundaries and therefore should be very fast.

唯一的其他选择,我不建议这样做,但是您可以使用来自Category和Collection的集合,并从可变集合中获得并集.每次我尝试该方向时,速度都会比进入数据库慢.我认为这种逻辑最好在数据库级别完成.

The only other option and I do not recommend it but you can play with the sets coming from Category and Collection and get a union from a mutable set. Every time I have experimented with that direction it was slower then going to the database. That kind of logic is best done at the database level in my opinion.

这篇关于CoreData性能:取决于更多的关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆