Home > Net >  Swift CoreData: accessing relationship is slower than just fetching by predicate - is it designed th
Swift CoreData: accessing relationship is slower than just fetching by predicate - is it designed th

Time:11-30

In my app I have 100 libraries that contain 5000 books each.

If I want to print 10 libraries and their 10 most recent additions, I can either fetch them all by accessing the relationship, then .suffix the returned NSSet and run a sort OR I can find the libraries by leaving a libraryID property that I can later use in an NSPredicate such as the following:

let fetchRequest = ... "Library"
let sort = NSSortDescriptor(key: "some key for ordering", ascending: false)
fetchRequest.sortDescriptors = [sort]
fetchRequest.fetchLimit = 10

let libraries = try context.fetch(fetchRequest) as? [Library]

for library in libraries {

    let fetchRequest = "Book"
    fetchRequest.fetchLimit = 10
    let predicate = NSPredicate(format: "libraryID == %@", library.id ?? "")
    fetchRequest.predicate = predicate
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "added date", ascending: false)]
    
    ...

}

What I do not understand is why the second option uses 15% of the CPU, whereas accessing the relationship directly is about 10 times slower.

My understanding of databases was that we have relationships in place to prevent doing exactly these kinds of things, somewhat hardcoding the ID of a parent property into a child property because now I am questioning what relationships are even good for.

There is one thing where I could see a relationship coming along useful, namely if we were able to perform a .fetch right on the Library object or it's books relationship - is that possible? Because then we wouldn't have to scan the whole table each time but instead only search within the entries of the relationship.

CodePudding user response:

Accessing via the relationship, then sorting and discarding 4950 / 5000 items means that all of that processing has to be done in memory. Using fetch requests means that you can get the database to do the work.

If you have a relationship between the library and its books, you can use that in a predicate. In your code above, that would be something like:

let predicate = NSPredicate(format: "library == %@", library)

That will likely be faster than storing the ID, unless you have an index added on library ID.

  • Related