Entity Inheritance Slowdowns
Core Data/SwiftData does not create separate tables for each subclass. Instead, it merges data from the parent entity and all its child entities into a single table (usually named after the parent entity).
[…]
- The Wide Table Problem: If there are many types of child entities with distinct attributes, this table will end up with a massive number of columns (a “Wide Table”). Even in the Swift 6 / iOS 26 environment, while hardware has improved, loading wide rows containing a vast number of
NULLvalues still consumes extra memory bandwidth.- Index Efficiency: Since all subclasses share a single table, the indexes can become bloated, potentially slowing down insertions and updates.
- Data Migration: Modifying the model of any single subclass (e.g., adding a property) requires touching this massive core table that holds all the data.
I think the most important performance tip is that using inheritance can really slow down fetches. If you try to fetch a particular entity using an indexed property, Core Data may have to do a lot of extra row scanning.
Sometimes, it will use the property index but then have to scan to find the matches that are of the right entity. This can be addressed by making a compound index that contains both the property and Z_ENT. With Core Data, you can do this by specifying the entity key path. I haven’t see any indication that it’s possible with Swift Data.
Other times, it will use the Z_ENT index in preference to the property index, which can be a really bad a idea if there are many objects with matching entities but few with matching properties. Because the Z_ENT in the WHERE clause is generated by Core Data, you can’t use noindex: to prevent it from using that index. It can be faster to fetch on the base entity, e.g. intentionally fetch objects that are of the wrong type but at least using the right index, and then filter for the desired entity later. With my data, it’s fine to do this in RAM because there aren’t many matches. But you can also check the entity (against a string) in the fetch request’s predicate. If your desired entity has subentities, you’ll need to check against all their names. Again, I don’t know how to do this with Swift Data.
Previously:
4 Comments RSS · Twitter · Mastodon
I remember this issue in particular biting us in the behind around on 2010-2011 era iPhones (single core, dual core just emerging). I think we ended up duping some of the entities to sidestep the issue. We still wanted to use the visual model editor in Xcode and its code generator, so we ended up modifying the model's entity descriptions to duplicate the base entities and their properties, recreate the entity inheritance tree, and used the same classes generated from the visual model with the duplicated entities. I don't remember all the intrigues, I think it created some limitations over how objects were being created, but it worked really well.
It's amazing how much Core Data has remained formant and stuck. I think the last major updates were around 2011, when the queue model and the custom incremental store support were introduced. Since then, I don't think there has been anything major. We met members of the Core Data team (Ben and someone else but I don't remember her name) in WWDC 2013 and they seemed very enthused to hear how we stress the system with out complex system, and it seemed like Core Data is a technology Apple invests in. I wonder what happened. Did they lose the talent? SwiftData is a joke even compared to Core Data.
@Léo Personally, I don’t like the code generation. If you give that up, you can do stuff like you describe using regular class inheritance. Just because the entity hierarchy is flat doesn’t mean the class hierarchy has to be.
There was some big stuff after that like persistent history and derived attributes. But progress seems much slower than in the past. There’s a long list of stuff that they could do, longstanding pain points that seem relatively straightforward, and that I once thought would happen eventually, but now it seems almost dead. I think Ben is still around but now works on Swift Data (as does Debbie). I think Scott moved to another team.
@Michael But that is exactly what we did, we had a class deep class hierarchy with a flat database with duplicate properties. Sorry if I wasn't clear. Back then with the ObjC generator, it was pretty nice. Modifying the model's entities at runtime was also relatively straightforward. None of that is actually possible with SwiftData. Is heavyweight migration even implemented in Swift Data? Last I cursorily looked, I couldn't understand how one is supposed to do lightweight migration in there, let alone something more complex on a per-row basis. All of that stuff, while complex, was possible and feasible on Core Data. I guess it's some kind of a "challenge" for the team to build something around Swift, but I don't see how someone who worked on Core Data and all its existing capabilities, can settle on something like Swift Data. I saw settle because it has been available for several years now, but I don't see big steps forward with it (or any steps at all frankly).