Simple fetch with .@count predicate taking a long time (~30seconds)
I have 2 entities, A and B that have a many to many relationship.
The A entity has about 10,000 objects in, and B has about 20 objects.
Basically, A objects can be related to one or more B objects, and the B objects keep track of which A objects they are connected to. This is done with the inverse relationship setting.
I simply wish to return every B object that is not related to an A object. The fetch I am using is this:
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
[fetch setIncludesPropertyValues:NO];
[fetch setEntity:[NSEntityDescription entityForName:开发者_高级运维@"B" inManagedObjectContext:context]];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"aObjects.@count == 0"]];
return [context executeFetchRequest:fetch error:nil];
However, it the fetch execution is taking a very long time, approx. 30 seconds. I don't understand this, because although there is a large number of A objects, this fetch has nothing to do with them, and just needs to check the 20 B objects.
If I comment out the predicate so the fetch returns all of the B objects, then the fetch is really quick, as you'd expect for just fetching 20 objects. So it would seem that that predicate is getting some A objects involved and is causing it to take a long time!
Can anyone shed any light on why this is taking so long?
Edit:
I've got SQL debug information and here's what's output:
CoreData: sql: SELECT t0.Z_ENT, t0.Z_PK FROM ZTABLEVIEWOBJECT t0 WHERE ((SELECT COUNT(*) FROM ZTABLEVIEWOBJECT t1 JOIN Z_10BOBJECTS t2 ON t1.Z_PK = t2.Z_10AOBJECTS3 JOIN ZTABLEVIEWOBJECT t3 ON t2.Z_12BOBJECTS = t3.Z_PK WHERE (t0.Z_PK = t2.Z_12BOBJECTS) ) = ? AND t0.Z_ENT = ?)
CoreData: annotation: sql connection fetch time: 49.4198s
CoreData: annotation: total fetch execution time: 49.4240s for 0 rows.
I should add that both entity A and entity B inherit (have a parent) of a common TableViewObject entity, which holds common values between the two (such as table view section names and sort names etc). Hope this helps!
you can replace
aObjects.@count == 0
with
ANY aObjects == nil
It's drastically reduce the time of my query (iPhone OS 3.0). It also works for != nil
(@count != 0
).
If you're using an SQLite store, you can turn on SQL debug logging. Core Data will log all the SQL commands it's making to the console. I've found this very useful to discover something unexpected happening behind the scenes. It will also print out timing information for each SQL command!
To do this, double-click the Executable in your project, go to the Arguments tab, and add an argument:
-com.apple.CoreData.SQLDebug 1
If I am understanding you correctly, you have a many-to-many relationship between these objects and that may be causing your issue. In a many-to-many there is a join table between B and A and that join table is probably getting hit hard. I would be quite curious to see the SQL that is being generated with your fetch.
UPDATE
Try changing your predicate to be "aObjects == nil" and see what happens. Because it is a many-to-many relationship that is the only other predicate that I can think of that might give you the results you are looking for.
I guess this is a little bit late, but maybe this will help others that run into this problem. The reverse relationship on bObjects
is an attribute of bObjects
and represented as an NSSet
in bObjects
. If either the NSSet
is nil
or the count of objects in the NSSet
is zero, then there are no aObjects
related to the particular bObject
.
Testing for the aObjects.@count
requires both tables representing the objects to be queried and is generating some really ugly SQL. What you are attempting here needs to look no further then the bObject
.
精彩评论