Fixing predicated NSFetchedResultsController/NSFetchRequest performance with SQLite backend?

删除回忆录丶 提交于 2019-12-05 20:33:02

This is an on-going problem for many of us trying to use Core Data on the iPhone for larger databases or more complex schemas. My profile has links to a couple different SO questions related to this -- in the context of full text searching.

Not all apps are dog slow just by applying a predicate to a to-many relationship, so there's more to it. See Apple's performance document. Set -com.apple.CoreData.SQLDebug 1.

Check that there's an index, if appropriate. Make sure there are no sql functions (such as format/type conversions) being called that keep sqlite from efficiently joining or using an index.

If you have a lot of rows and there are many attributes in your entity there may be memory issues. Consider splitting a single entity into a smaller one with a few attributes used for your search and pull in the rest when needed.

If your predicate is more complex than the to-many relationship part, then you might experiment with searching in two steps. E.g. the SQL might be inefficiently joining and then filtering instead of filtering and then joining. But doing this would break NSFetchedResultsController. Still, it might shed some light on the trouble.

I would not do something like pack ObjectIDs into an attribute to make your own to-many foreign key reference. Sounds like a horrible hack surely to dissuade you from using Core Data seriously... yet the advantages of Core Data are numerous.

Experiment with removing or adding the reverse relationship. I found in one case that my query ran much faster without the reverse relationship. The downside was that removing the reverse relationship bloated my database.

Let us know what you find.

The practical solution to this for me was to just switch to Core Data binary store that has much better performance. I did not investigate whether I can improve Core Data SQLite performance with my current app situation.

A binary story will load the entire data set into memory which will cause a memory issue on some devices. Instead you should re-write your predicate.

Since your relationships are double-sided (right?) you can come at it from the other side and you probably don't need a NSFetchedResultsController at all for this situation. Presume you have:

MyWidgetEntity <--->> SomethingEntity

Since you already have a reference to an instance of SomethingEntity you just ask it for it's widget via:

id widget = [mySomethingInstance valueForKey:@"widget"];

In the situation where you have:

MyWidgetEntity <<-->> SomethingEntity

You can get access to all of the associated widgets via:

NSSet *widgets = [mySomethingInstance valueForKey:@"widgets"];

No NSFetchedResultsController is needed because you can turn this set into an array and sort it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!