Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's happening underneath a Fetch Request Template that improves performance?

I was curious if there was a performance gain from creating a Fetch Request Template versus programmatically creating NSFetchRequest so I wrote some tests to measure this. Here's the source on github.

Same order of difference in Simulator and on iPhone (measuring time interval to do a bunch of fetches):

just creating an NSFetchRequest:          4.399674
creating a Fetch Request Template:        0.501369
NSFetchRequest with field indexed:        0.407068
Fetch Request Template and field indexed: 0.281876

It turns out there's about 7~9 times performance gain in creating a Fetch Request Template. I thought maybe it's creating the proper index underneath but when I created an Fetch Request Template that matches on an indexed field, there's even a further performance benefit.

Ok, nice to know that this is the case, but I would very much like to know what the heck is happening underneath the Fetch Request Template that accounts for performance gains?

like image 206
Jinyoung Kim Avatar asked Jun 24 '12 06:06

Jinyoung Kim


People also ask

What does fetch API do?

The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest , but the new API provides a more powerful and flexible feature set.

Is fetch a GET request?

Fetch defaults to GET requests, but you can use all other types of requests, change the headers, and send data.

What is fetch request in Swift?

Use a FetchRequest property wrapper to declare a FetchedResults property that provides a collection of Core Data managed objects to a SwiftUI view. The request infers the entity type from the Result placeholder type that you specify. Condition the request with an optional predicate and sort descriptors.


2 Answers

Update

After some profiling with Instruments, it turns out [NSPredicate predicateWithFormat:] is not the culprit here!

The actual cause of the performance difference is sort descriptors.

The non-template tests are using an NSFetchedResultsController, which requires a sort descriptor, whereas the template-based ones do not specify a sort descriptor.

If you add a sort descriptor to all the tests, the performance evens out (with the exception of the indexed case.)


Original (wrong) answer

The performance penalty is because your 'just creating a NSFetchRequest' test calls [NSPredicate predicateWithFormat:] for each iteration of the loop - this is very slow!

Think about it - [NSPredicate predicateWithFormat:] has to parse the string and basically compile it into the internal representation used by Core Data.

The usual solution is to only call [NSPredicate predicateWithFormat:] once, and then use [NSPredicate predicateWithSubstitutionVariables:] to specify the values that will be compared by the predicate - this is covered in the Core Data Documentation - Efficiently Importing Data

To create a predicate from a formatted string, the framework must parse the string and create instances of predicate and expression objects. If you are using the same form of a predicate many times over but changing the value of one of the constant value expressions on each use, it is more efficient to create a predicate once and then use variable substitution (see “Creating Predicates”).

like image 71
Nick Dowell Avatar answered Nov 04 '22 16:11

Nick Dowell


From the documentation:

Stored fetch requests can include placeholders for variable substitution, and so serve as templates for later completion. Fetch request templates therefore allow you to pre-define queries with variables that are substituted at runtime.

Also, see the Stored Fetch Requests section of the NSManagedObjectModel Class Reference.

It seems like the biggest advantage might come from the fact that the query does not have to be built at runtime -- it is pre-built and then variables are substituted into the query when appropriate.

like image 25
Michael Frederick Avatar answered Nov 04 '22 14:11

Michael Frederick