views:

517

answers:

2

I am trying to figure out the best way to bulk delete objects inside of my Core Data database.

I have some objects with a parent/child relationship. At times I need to "refresh" the parent object by clearing out all of the existing children objects and adding new ones to Core Data. The 'delete all' portion of this operation is where I am running into trouble. I accomplish this by looping through the children and calling deleteObject for each one.

I have noticed that after the NSManagedObjectContext:Save call following all of the deleteObject calls is very slow when I am deleting 15,000 objects.

How can I speed up this call? Are there things happening during the save operation that I can be aware of and avoid by setting parameters different or setting up my model another way? I've noticed that memory spikes during this operation as well. I really just want to "delete * from".

Thanks.

A: 

Check the relationship dependency graph: a cascade of deletes triggered by the initial deletion will slow things down. If those deletes are unnecessary then change the deletion rule.

Alex Reynolds
A: 

Supposing that you have in your Core Data model a parent and a child entities, and the parent has a to-many relationship to child called children, you should be able to delete all of the child objects without looping as follows:

NSManagedObject *parentObject = ...;
[parentObject setValue:nil forKey:@"children"];

or using the Core Data generated method

- (void)removeChildren:(NSSet *)value;

NSSet *children = [parentObject valueForKey:@"children"];
[parentObject removeChildren:children];

I am not sure if this will speed up the NSManagedObjectContext save operation. Please let me know about the performances.

unforgiven
Thanks, I'll try this out and post my results. Do these methods cause the objects to be removed from the sqlite db? I don't want to disconnect and orphan the objects.
toofah
Yes, the object are deleted. But I do not understand your point: deleting them all in a loop and then saving the context achieves exactly the same effect. The only difference may be in performances, and your results will tell us if this is the case or not.
unforgiven
I like these changes because they seem to simplify the code a little bit, but they don't seem to fix the performance and memory issues.When I put this amount of data into Core Data I do some pretty hefty memory management to keep things under control. Maybe I will need to apply some of the same principles here: create my own NSAutoreleasePool and drain it every so often to get rid of Core Data's temporary objects, reset the managed object context as well at this point to make sure we are not holding on to unneeded objects from relationships. Maybe this will speed things up as well.
toofah
OK, that solved my memory problems, but didn't do much for performance; although the for loop does provide a way for me to show progress through a progress bar. Essentially my changes were the following: Create an NSAutoreleasePool. Loop through children objects and delete them in chunks of X. After every X deletions, reset the NSManagedObjectContext and drain the autorelease pool. Then release the pool when finished.
toofah