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: