Reputation: 233
I am using parse as cloud storage, combined with local data store for general access. I do find that querying the local data storage takes a lot longer than I expected. This is particularly noticeable when using the data to populate tables or update graphical views. Equivalent functions in coredata are near instantaneous and the results are very good. Whilst I do not expect the performance of coredata, it is much slower than I might expect for offline access and I wonder if I am doing something wrong?
Here is an example query :
PFQuery *query = [PFQuery queryWithClassName:LOCATION_OBJECT];
[query fromLocalDatastore];
[query whereKey:MESSAGE_TO_FIELD equalTo:user.username];
[query orderByDescending:CREATED_FIELD];
NSLog(@"Query started");
NSArray* res = [query findObjects];
NSLog(@"Query finished, found %lu objects", (unsigned long)[res count]);
Executing on a 2015 iPad mini the sort of timings I see are as follows :
2015-06-16 18:56:38.883 app[1744:1668474] Query started
2015-06-16 18:56:38.885 app[1744:1668474] Warning: A long-running operation is being executed on the main thread.
Break on warnBlockingOperationOnMainThread() to debug.
2015-06-16 18:56:39.177 app[1744:1668474] Query finished, found 17 objects
I do understand that Parse is offering much more than just a database, nevertheless this query takes 0.292secs which seems an age. For my app, I use this sort of operation fairly frequently as a user navigates across the screen. With coredata the results were excellent, with Parse the lag is very noticeable. It is worth mentioning that results are similar on the simulator. The warning parse issues when you do this sort of thing is not encouraging, but in any case, my questions are two fold :
1) Have I missed any performance adjustments/settings in Parse? 2) Have other people who have used Parse found similar performance or have any advice?
At this point, it looks like I will need to use coredata in the app and write my own routines to push that data to Parse's cloud, which is a lot more work than I was hoping for.
Thanks for your time.
Update 30Jun15
Thanks for the comments, as per those comments, here is example performance from doing it the way Parse wants you to do it. As before, performance is still poor when compared with coredata. Example code :
PFQuery *query = [PFQuery queryWithClassName:LOCATION_OBJECT];
[query fromLocalDatastore];
[query whereKey:MESSAGE_TO_FIELD equalTo:user.username];
[query orderByDescending:CREATED_FIELD];
NSLog(@"Query started ... ");
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(@"Query finished ... ");
if(!error)
NSLog(@"Found %lu message records in local datastore", (unsigned long)[objects count]);
else
NSLog(@"Parse error pulling messages from datastore: %@ %@", error, [error userInfo]);
}];
Performance in same iPad :
2015-06-30 10:32:09.633 MvBii[205:5172] Query started ...
2015-06-30 10:32:09.948 MvBii[205:5172] Query finished ...
2015-06-30 10:32:09.948 MvBii[205:5172] Found 100 message records in local datastore
Query takes 0.315 seconds. Now, as before, I'm not saying this is bad per se and probably for many applications it is just fine, but it is orders of magnitude worse than coredata and is too slow for my app. As the user navigates around the screen graphics are drawn as a result of this query, and I can't update the screen quick enough, using parse, in response to the user input. Using coredata the results are very good.
My main question is simply whether this query time is in accord with any one else's experience? I wonder if there is anything peculiar to my app or data set? The data set is not large (< 200 items), the parse object is just strings and ints. I still really want to use Parse for all of the other facilities it provides. Maybe it is simply my expectations are off, but it seems a long time for a basic query.
Upvotes: 0
Views: 742
Reputation: 233
Parse is now open source, so I have investigated this a bit further. Here are my findings.
Parse builds a queue of tasks that are executed sequentially, in the order that they are requested. This is regardless of how the request is made (foreground, background or background with callback). Tasks are pulled off the queue to be processed and in essence it takes about a few hundred ms to get the task, create a thread for the task and then execute said task. Note that the next task in the list is not processed until the previous one completes. So, if you push a number of tasks to parse quickly, the tasks are queued and you will see the times grow linearly with the number of tasks. Here is some experimental code :
PFQuery* query = [PFQuery queryWithClassName:ANNOTATION_OBJECT];
[query fromLocalDatastore];
[query orderByAscending:CREATED_FIELD];
NSLog(@"Query 1 started");
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
NSLog(@"Query 1 finished");
}];
query = [PFQuery queryWithClassName:ANNOTATION_OBJECT];
[query fromLocalDatastore];
[query orderByAscending:CREATED_FIELD];
NSLog(@"Query 2 started");
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
NSLog(@"Query 2 finished");
}];
query = [PFQuery queryWithClassName:ANNOTATION_OBJECT];
[query fromLocalDatastore];
[query orderByAscending:CREATED_FIELD];
NSLog(@"Query 3 started");
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
NSLog(@"Query 3 finished");
}];
So 3 queries are pushed to parse in rapid succession. They are queued up so query 3 takes 3 times as long to complete as query 1.
2015-09-23 14:29:28.419 MvBii[257:59781] Query 1 started
2015-09-23 14:29:28.420 MvBii[257:59781] Query 2 started
2015-09-23 14:29:28.421 MvBii[257:59781] Query 3 started
2015-09-23 14:29:28.658 MvBii[257:59781] Query 1 finished
2015-09-23 14:29:28.854 MvBii[257:59781] Query 2 finished
2015-09-23 14:29:29.011 MvBii[257:59781] Query 3 finished
For my app, the query time of a few hundred ms was just about ok, but as the user navigated the requests would stack up meaning the ones at the end of the queue were taking a very long time. This is not unreasonable of parse, but one should be aware that this is how it behaves. If there is a pin or a save in the middle of this task, the query will be delayed by the length of time the pin or the save takes. This could be a few seconds.
Parse offers a lot for free, just be aware if you request a lot of it in quick succession, you might see some performance issues depending upon your app and your needs.
Upvotes: 6