Re: Core Data fetch performance

2012-11-16 Thread Mike Abdullah

On 12 Nov 2012, at 14:15, Joerg Simon j_si...@mac.com wrote:

 This summs it up really nicely:
 
 http://wbyoung.tumblr.com/post/27851725562/core-data-growing-pains
 
 Links to radar bug reports are within the blog post.
 
 The conclusion it is not usable does not hold under iOS6, since nested 
 contexts work quite wonderfully there, but it shows problems under iOS5.
 
 Generally if you use performBlock and not performBlockAndWhait and do not use 
 a fetched results controller at all and some other tricks, you can get it 
 working quite well also under iOS5, but actually the code you produce is 
 uglier than doing it manually the old way using thread confinment and merge 
 by hand. At least in my experience.
 
 But under iOS6 nested contexts rock!

So to summarise:

- Child contexts synchronously route through their parent to perform fetches. 
The author thinks this is a mistake; I consider it an expected consequence of 
the design

- Making changes into a parent context can be slow with no mention of a radar 
or details of any possible fix

- Child contexts in iOS5/OS X 10.7 are pretty buggy when it comes to 
propogating changes *down* from their parent. This is where iOS 6/OS X 10.8 
appears to have improved matters.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-12 Thread Bob Cromwell
Hi Hunter,

I am very interested in what  bugs they fixed.  Could you please share more 
about it , e.g.  an official bug fix report ?  

Thanks

Bob

 The API changes came in iOS 5 but in iOS 6 they fixed enough bugs to make it 
 work right. :-)

 On Nov 11, 2012, at 4:50 PM, Rick Mann rm...@latencyzero.com wrote:
 
 GCD, along with the Core Data changes in iOS 5 and 6 for handling 
 concurrency, make this much easier than it used to be (or at least cleaner 
 and harder to screw up as badly).
 
 By the way, what were the changes in iOS 6? I can't find specific Core Data 
 notes for iOS 6, only iOS 5. Thanks!
 
 
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 Please do not post admin requests or moderator comments to the list.
 Contact the moderators at cocoa-dev-admins(at)lists.apple.com
 
 Help/Unsubscribe/Update your Subscription:
 https://lists.apple.com/mailman/options/cocoa-dev/bob.cromwell2012%40gmail.com
 
 This email sent to bob.cromwell2...@gmail.com


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-12 Thread Joerg Simon
This summs it up really nicely:

http://wbyoung.tumblr.com/post/27851725562/core-data-growing-pains

Links to radar bug reports are within the blog post.

The conclusion it is not usable does not hold under iOS6, since nested contexts 
work quite wonderfully there, but it shows problems under iOS5.

Generally if you use performBlock and not performBlockAndWhait and do not use a 
fetched results controller at all and some other tricks, you can get it working 
quite well also under iOS5, but actually the code you produce is uglier than 
doing it manually the old way using thread confinment and merge by hand. At 
least in my experience.

But under iOS6 nested contexts rock!
Cheers, Jörg

On Nov 12, 2012, at 1:58 PM, Bob Cromwell bob.cromwell2...@gmail.com wrote:

 Hi Hunter,
 
 I am very interested in what  bugs they fixed.  Could you please share more 
 about it , e.g.  an official bug fix report ?  
 
 Thanks
 
 Bob
 
 The API changes came in iOS 5 but in iOS 6 they fixed enough bugs to make it 
 work right. :-)
 
 On Nov 11, 2012, at 4:50 PM, Rick Mann rm...@latencyzero.com wrote:
 
 GCD, along with the Core Data changes in iOS 5 and 6 for handling 
 concurrency, make this much easier than it used to be (or at least cleaner 
 and harder to screw up as badly).
 
 By the way, what were the changes in iOS 6? I can't find specific Core Data 
 notes for iOS 6, only iOS 5. Thanks!
 
 
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 Please do not post admin requests or moderator comments to the list.
 Contact the moderators at cocoa-dev-admins(at)lists.apple.com
 
 Help/Unsubscribe/Update your Subscription:
 https://lists.apple.com/mailman/options/cocoa-dev/bob.cromwell2012%40gmail.com
 
 This email sent to bob.cromwell2...@gmail.com
 
 
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 Please do not post admin requests or moderator comments to the list.
 Contact the moderators at cocoa-dev-admins(at)lists.apple.com
 
 Help/Unsubscribe/Update your Subscription:
 https://lists.apple.com/mailman/options/cocoa-dev/j_simon%40mac.com
 
 This email sent to j_si...@mac.com


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Core Data fetch performance

2012-11-11 Thread Rick Mann
I'm seeing a substantial degradation in Core Data fetch performance after just 
a few thousand objects, in the simulator on a beefy MacBook Pro.

My app loads data from the web, then uses an integer key in each downloaded 
record to find the local record in Core Data. So I do a lot of queries like 
this:

{
NSFetchRequest* req = [[NSFetchRequest alloc] init];
req.fetchLimit = 1;

NSManagedObjectContext* moc = self.managedObjectContext;
NSEntityDescription* entity = [NSEntityDescription entityForName: 
@MissionEvent
  inManagedObjectContext: moc];
req.entity = entity;

NSPredicate* pred = [NSPredicate predicateWithFormat: @keyShadow == %ld, 
inMEP.mId];
req.predicate = pred;

NSError*error = nil;
NSArray* events = [self.managedObjectContext executeFetchRequest: req 
error: error];
...
}

Basically, I query, the insert, over and over. As the number of records grows 
from 0 to 6000, the time it takes to execute this query grows from about 0.0007 
s to about 0.0126 s. Indexing is on for keyShadow:

sqlite explain query plan SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZCLOCKSHADOW, 
t0.ZDESC, t0.ZDISABLEDSHADOW, t0.ZDURATIONSHADOW, t0.ZKEYSHADOW, 
t0.ZLASTMODIFIED, t0.ZNAME, t0.ZSEQUENCESHADOW, t0.ZTIMESHADOW, t0.ZTYPESHADOW, 
t0.ZMISSION FROM ZMISSIONEVENT t0 WHERE  t0.ZKEYSHADOW = ?
   ... ;
sele  order  from  deta
  -    
0 0  0 SEARCH TABLE ZMISSIONEVENT AS t0 USING INDEX 
ZMISSIONEVENT_ZKEYSHADOW_INDEX (ZKEYSHADOW=?) (~10 rows)

This seems like pretty poor performance. Is this the best I can hope for?

Thanks,

-- 
Rick




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-11 Thread Hunter Hillegas
Do you have keyShadow set as indexed in the model? If not, you probably want to 
give that a try.

If you have all of the keys up front (i.e. this is a big batch update or insert 
from the Web Service data), you might consider loading all of the records at 
once and then using a predicate to find what you need. Something like:

//load all possible matches at once
NSFetchRequest *possibleEventsFetchRequest = [[NSFetchRequest alloc] 
initWithEntityName:@MissionEvent]; 
[possibleEventsFetchRequest setPredicate:[NSPredicate 
predicateWithFormat:@keyShadow IN %@, allPossibleKeyShadows]];
NSArray *possibleEvents = [self.managedObjectContext executeFetchRequest: 
possibleEventsFetchRequest error:nil];

//create a filter predicate
NSPredicate *indexMatchPredicate = [NSPredicate predicateWithFormat:@keyShadow 
== %ld, inMEP.mId];

//this now happens in memory
NSManagedObject *matchingObject = [[possibleEvents filteredArrayUsingPredicate: 
indexMatchPredicate] lastObject];

Hunter

On Nov 11, 2012, at 6:42 AM, Rick Mann rm...@latencyzero.com wrote:

 I'm seeing a substantial degradation in Core Data fetch performance after 
 just a few thousand objects, in the simulator on a beefy MacBook Pro.
 
 My app loads data from the web, then uses an integer key in each downloaded 
 record to find the local record in Core Data. So I do a lot of queries like 
 this:
 
 {
NSFetchRequest* req = [[NSFetchRequest alloc] init];
req.fetchLimit = 1;
 
NSManagedObjectContext* moc = self.managedObjectContext;
NSEntityDescription* entity = [NSEntityDescription entityForName: 
 @MissionEvent
  inManagedObjectContext: moc];
req.entity = entity;
 
NSPredicate* pred = [NSPredicate predicateWithFormat: @keyShadow == %ld, 
 inMEP.mId];
req.predicate = pred;
 
NSError*error = nil;
NSArray* events = [self.managedObjectContext executeFetchRequest: req 
 error: error];
...
 }
 
 Basically, I query, the insert, over and over. As the number of records grows 
 from 0 to 6000, the time it takes to execute this query grows from about 
 0.0007 s to about 0.0126 s. Indexing is on for keyShadow:
 
 sqlite explain query plan SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZCLOCKSHADOW, 
 t0.ZDESC, t0.ZDISABLEDSHADOW, t0.ZDURATIONSHADOW, t0.ZKEYSHADOW, 
 t0.ZLASTMODIFIED, t0.ZNAME, t0.ZSEQUENCESHADOW, t0.ZTIMESHADOW, 
 t0.ZTYPESHADOW, t0.ZMISSION FROM ZMISSIONEVENT t0 WHERE  t0.ZKEYSHADOW = ?
   ... ;
 sele  order  from  deta
   -    
 0 0  0 SEARCH TABLE ZMISSIONEVENT AS t0 USING INDEX 
 ZMISSIONEVENT_ZKEYSHADOW_INDEX (ZKEYSHADOW=?) (~10 rows)
 
 This seems like pretty poor performance. Is this the best I can hope for?
 
 Thanks,
 
 -- 
 Rick
 
 
 
 
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 Please do not post admin requests or moderator comments to the list.
 Contact the moderators at cocoa-dev-admins(at)lists.apple.com
 
 Help/Unsubscribe/Update your Subscription:
 https://lists.apple.com/mailman/options/cocoa-dev/lists%40lastonepicked.com
 
 This email sent to li...@lastonepicked.com


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-11 Thread Rick Mann

On Nov 11, 2012, at 9:57 , Hunter Hillegas li...@lastonepicked.com wrote:

 Do you have keyShadow set as indexed in the model? If not, you probably want 
 to give that a try.

Yeah, the key is indexed (as I pointed out in the original post :-))

 If you have all of the keys up front (i.e. this is a big batch update or 
 insert from the Web Service data), you might consider loading all of the 
 records at once and then using a predicate to find what you need. Something 
 like:

I do. I was thinking about this last night. I'm concerned that this may require 
too much memory, and building a string of 6400 IDs for the query to then 
format...sounds expensive. Can one build IN queries directly?

I could do it in small batches. In truth, there will generally be more new 
records than updated records, and by adding a created-date (I currently use a 
last-modified-date), I can determine if the record is new or updated. Then I 
can skip the fetch for most of the downloaded records. But that's such a big 
change.

I currently download on a separate thread, then call back to the main thread 
for each record. The intent was avoid doing Core Data work on a separate 
thread, and keep the UI responsive. But that doesn't really enable the second 
core, and it adds a lot of overhead. Maybe it's time to do the Core Data on the 
second thread, too. Pretty sure that will require substantial changes to the 
way my UI keeps up with updates.

-- 
Rick




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-11 Thread Hunter Hillegas
 Do you have keyShadow set as indexed in the model? If not, you probably want 
 to give that a try.
 
 Yeah, the key is indexed (as I pointed out in the original post :-))

Heh, I re-read your post like four times and only just now saw that notation. 
Whoops.

 If you have all of the keys up front (i.e. this is a big batch update or 
 insert from the Web Service data), you might consider loading all of the 
 records at once and then using a predicate to find what you need. Something 
 like:
 
 I do. I was thinking about this last night. I'm concerned that this may 
 require too much memory, and building a string of 6400 IDs for the query to 
 then format...sounds expensive.

It's possible that doing them all in one hit might be too much… As with most 
workloads, you may need to experiment to find a happy medium.

 Can one build IN queries directly?

I'm not entirely sure I know what you mean by 'directly' in this context.

 I currently download on a separate thread, then call back to the main thread 
 for each record. The intent was avoid doing Core Data work on a separate 
 thread, and keep the UI responsive. But that doesn't really enable the second 
 core, and it adds a lot of overhead. Maybe it's time to do the Core Data on 
 the second thread, too. Pretty sure that will require substantial changes to 
 the way my UI keeps up with updates.

GCD, along with the Core Data changes in iOS 5 and 6 for handling concurrency, 
make this much easier than it used to be (or at least cleaner and harder to 
screw up as badly).
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Core Data fetch performance

2012-11-11 Thread Hunter Hillegas
 I do. I was thinking about this last night. I'm concerned that this may 
 require too much memory, and building a string of 6400 IDs for the query to 
 then format...sounds expensive. Can one build IN queries directly?

I should note, I've done this quite successfully with workloads in the ~500 
ID/possible matches range but never something quite as big as you're suggesting.
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-11 Thread Rick Mann

On Nov 11, 2012, at 15:54 , Hunter Hillegas li...@lastonepicked.com wrote:

 Heh, I re-read your post like four times and only just now saw that notation. 
 Whoops.

It happens.

 Can one build IN queries directly?
 
 I'm not entirely sure I know what you mean by 'directly' in this context.

Instead of using -predicateWithFormat:, creating an NSComparisonPredicate, 
perhaps type NSInPredicateOperatorType, and pass an array of NSNumbers to it. 
Not sure that's how it works.

 I currently download on a separate thread, then call back to the main thread 
 for each record. The intent was avoid doing Core Data work on a separate 
 thread, and keep the UI responsive. But that doesn't really enable the 
 second core, and it adds a lot of overhead. Maybe it's time to do the Core 
 Data on the second thread, too. Pretty sure that will require substantial 
 changes to the way my UI keeps up with updates.
 
 GCD, along with the Core Data changes in iOS 5 and 6 for handling 
 concurrency, make this much easier than it used to be (or at least cleaner 
 and harder to screw up as badly).

I'll have to look into it. I also need my UI to populate as the loads are 
happening, at least partly, which means no longer doing one big UI update at 
the end of the operation.

Thanks,

-- 
Rick




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-11 Thread Rick Mann

On Nov 11, 2012, at 15:54 , Hunter Hillegas li...@lastonepicked.com wrote:

 GCD, along with the Core Data changes in iOS 5 and 6 for handling 
 concurrency, make this much easier than it used to be (or at least cleaner 
 and harder to screw up as badly).

By the way, what were the changes in iOS 6? I can't find specific Core Data 
notes for iOS 6, only iOS 5. Thanks!
-- 
Rick




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-11 Thread Rick Mann

On Nov 11, 2012, at 23:16 , Hunter Hillegas li...@lastonepicked.com wrote:

 The API changes came in iOS 5 but in iOS 6 they fixed enough bugs to make it 
 work right. :-)

Hrm, does that mean it won't work on iOS 5.1?

-- 
Rick




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance

2012-11-11 Thread Hunter Hillegas
The API changes came in iOS 5 but in iOS 6 they fixed enough bugs to make it 
work right. :-)

On Nov 11, 2012, at 4:50 PM, Rick Mann rm...@latencyzero.com wrote:

 GCD, along with the Core Data changes in iOS 5 and 6 for handling 
 concurrency, make this much easier than it used to be (or at least cleaner 
 and harder to screw up as badly).
 
 By the way, what were the changes in iOS 6? I can't find specific Core Data 
 notes for iOS 6, only iOS 5. Thanks!


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Core Data fetch performance, design pattern sought

2010-09-02 Thread Sean McBride
Hi all,

I have 2 CoreData entities, Foo and Bar.  Both have 'name' string
attributes.  There are textfields allowing the user to rename any Foo
and any Bar.  Assume no 2 Foos can have the same name; likewise for
Bars.  There is a relationship between Foo and Bar.  I want a Foo to be
related to a Bar if and only if their names match.  That is, when the
user renames a Foo (or a Bar), I want to add/break a relationship
between the Bar (or Foo) of the same name.

Up to now I've done this by implementing Foo's setName: to 1) change
self's name and 2) fetch Bars of the same name.  Likewise for Bar.  This
works.  But it's slow if a single user action changes many names at once
because many redundant fetches are performed.

Any suggestions on a good pattern to solve this?

Thanks,

--

Sean McBride, B. Eng s...@rogue-research.com
Rogue Researchwww.rogue-research.com
Mac Software Developer  Montréal, Québec, Canada


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch performance, design pattern sought

2010-09-02 Thread Quincey Morris
On Sep 2, 2010, at 14:46, Sean McBride wrote:

 I have 2 CoreData entities, Foo and Bar.  Both have 'name' string
 attributes.  There are textfields allowing the user to rename any Foo
 and any Bar.  Assume no 2 Foos can have the same name; likewise for
 Bars.  There is a relationship between Foo and Bar.  I want a Foo to be
 related to a Bar if and only if their names match.  That is, when the
 user renames a Foo (or a Bar), I want to add/break a relationship
 between the Bar (or Foo) of the same name.
 
 Up to now I've done this by implementing Foo's setName: to 1) change
 self's name and 2) fetch Bars of the same name.  Likewise for Bar.  This
 works.  But it's slow if a single user action changes many names at once
 because many redundant fetches are performed.

According to the above, what you really want is an implicit relationship 
between Foos and Bars, based on name identity. That's relationship in the 
design sense, not in the Core Data sense.

a. Have you asked the question whether you need an explicit (Core Data) 
relationship as well? What are the implications of traversing your object graph 
by name (i.e. by fetching according to name) instead of by explicit 
relationship?

b. Assuming you do need the explicit relationship, I'd suggest it's functioning 
as a cache for the implicit relationship. So, you could implement it that 
way. Override the Core Data relationship property accessors, and try using the 
cached primitive relationship first. If that fails, fetch the related object 
by name and cache the result in the primitive relationship. (Specifically, I 
mean: if the object has an existing related object, check the related object's 
name. If it doesn't match, or if there is no related object, then fetch the 
related object.)

If the related object is in memory, this access is slower but not incredibly 
slower than the built-in accessor (unless you have very stringent performance 
requirements). If the related object is not in memory, or it the relationship 
is stale, then the access is also going to cost you a fetch.

There's probably another viable intermediate option, too. When changing a name, 
you could defer refreshing explicit relationships until any explicit 
relationship is, er, explicitly accessed. At that point you could refresh all 
accumulated stale relationships. That would bunch up the update processing, but 
might reduce unnecessary fetching, compared to your original proposal.

It all kind of depends on your performance requirements. Possibly even, 
redundant fetches are cheaper than anything I'm suggesting, in your usage 
scenario.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com