9

Is there a way to tell Core Data to not put all your entities into one table when they all inherit from a base entity? Here's an example: We have an "Entity" object and we have a "Person" and "Product" that inherit from "Entity". Core data creates an ZENTITY table with the combined fields for "Entity", "Person" and "Product". What we want is for core data to create two separate tables, one for "Person" and one for "Product".

Is this even possible? Nothing anywhere online talks about this...

jjxtra
  • 20,415
  • 16
  • 100
  • 140

4 Answers4

13

I did measurements and CoreData's performance is totally degraded when using inheritance on real (~50000 objects, 20+ classes, each having ~5 relationships, most of them to-many) data. I do not use CD for toy apps with 1000 objects - it's a real huge app and performance penality is unjustified. Even worse, creating small objects takes lots of ssd and memory space because of this stupid implementation.

The only real solution (i DO NEED inheritance) is to replace the default sqlite persistent store with manual implementation using NSIncrementalStore from iOS 5 and up. However, fetch request to SQL translation and model updates are really hard to implement.

And yes, I know that core data is not an SQL. But I expect it to work comparably fast when dealing with lots of data - otherwise it would be stupid to ever use it in real world apps.

Terminus
  • 925
  • 10
  • 23
  • 1
    Same experience for us, it killed performance. We ended up just getting rid of the base class and duplicating all our properties. – jjxtra Jul 13 '13 at 13:45
  • I accept this answer simply because the answer to this solution is to not use inheritance with core data – jjxtra Aug 13 '13 at 19:12
10

According to the detailed article by Florian Kugler, the solution is to use inheritance in your model code but not in your schema:

Entity Hierarchy vs. Class Hierarchy

Managed object models offer the possibility to create entity hierarchies, i.e. we can specify an entity as the parent of another entity. This might sound good, for example, if our entities share some common attributes. In practice, however, it’s rarely what you would want to do.

What happens behind the scenes is that Core Data stores all entities with the same parent entity in the same table. This quickly creates tables with a large number of attributes, slowing down performance. Often the purpose of creating an entity hierarchy is solely to create a class hierarchy, so that we can put code shared between multiple entities into the base class. There is a much better way to achieve this though.

The entity hierarchy is independent of the NSManagedObject subclass hierarchy. Or put differently, we don’t need to have a hierarchy within our entities to create a class hierarchy.

https://www.objc.io/issues/4-core-data/core-data-models-and-model-objects/

Chris Conover
  • 8,889
  • 5
  • 52
  • 68
3

Nothing anywhere online talks about this..

That's because tables have nothing to do with Core Data.

Core Data is not SQL. Entities are not tables. Objects are not rows. Columns are not attributes. Core Data is an object graph management system that may or may not persist the object graph and may or may not use SQL far behind the scenes to do so. Trying to think of Core Data in SQL terms will cause you to completely misunderstand Core Data and result in much grief and wasted time.

In this, case your SQL trained intuition for how to optimize SQL will cause you to waste a lot of time. If your peaking into your SQLite store as you develop, you are using Core Data incorrectly. It's not just an object wrapper for SQL.

It was a design decision to put all entities with the same inheritance into the same SQL table when Core Data is using an SQLite store. However, that has little functional relevance in most cases as Core Data manages the object graph first and cares little about the details of persistence. If you have a large number of objects of the same entity inheritance tree you might hit some performance issue at the very high end e.g. 20k+ objects but otherwise not.

In any case, it can't be changed. Core Data intentionally hides the its SQL implementation because SQL is just one persistence option out of many.

Premature optimization is the root of all evil. Build in the logically best fashion and then test. Only if you encounter an edge case in testing should you worry about the minutia of the SQL store.

TechZen
  • 64,370
  • 15
  • 118
  • 145
  • 7
    In our case performance is suffering terribly, so the underlying implementation is VERY important, and in the case of all the objects going into one table is very bad. That's what you get with a black box object mapping solution though. Works good most of the time, and when it doesn't, it's hard to deal with... – jjxtra Mar 14 '11 at 06:00
  • The first thing to do is to look back at your data model and see if you really need the entity inheritance you have set up. The most common reason is because you have a relationship to an abstract entity and then many sub-entities that all need to be able to be in the relationship. If you don't have that need then there isn't any other function that requires entity inheritance. You can probably create different entities altogether. – TechZen Mar 14 '11 at 22:10
  • I have the same problem. Data model is okey, the inheritance has its logic. I know that performance will be terrible in future if I don't optimize the SQL behind core data know. I can't just ignore it. I will probably remove inheritance from model and leave it for the entity classes. I think this is a bad decision for Core Data because it's a light wrapper for SQL. We are using SQL predicates everywhere, so we can't just ignore SQL. It would be nice to have some property that will prevent core data to merge everything into one table. – Sulthan Sep 02 '11 at 09:42
  • 1
    @Sulthan -- Core data isn't an SQL wrapper and you don't know what the overall performance will be until you stress test it. In my experience, most concerns about Core Data SQL performance are unfounded. There is a lot more going on than just SQL lookups. Core Data is managing the entire model layer of which lookups are just a part. – TechZen Sep 02 '11 at 15:31
  • In most cases, putting objects of the same entity inheritance in the same table is obviously the optimum solution. If you have a single relationship which can contain objects sharing entity inheritance, then it would clearly be quicker and simpler to search one table than it would be to perform multiple searches in multiple tables. I think most problems with overloaded tables come from people overusing entity inheritance because they think it has to work like class inheritance. – TechZen Sep 02 '11 at 15:38
  • You know, in principle, it should work like class inheritance. It should define an is-a relationship. The problem is that Core Data don't know which fetch queries will be needed and so it cannot optimize tables beforehand. And I can know the performance pretty well even without stress tests. I am not a beginner - I know how SQLite queries work. And I think you are mistaken with the "model" layer. Core data is managing the "data" layer :) – Sulthan Sep 02 '11 at 18:11
  • 1
    @Sulthan -- Your intuition you've developed working with SQL won't serve you well with Core Data. SQL is just an option for Core Data and is a rather recent addition at that. It is not central to Core Data's functioning. Core Data is primarily an object-graph management systems with optional persistence in several optional formats. It's primary function is creating the model layer regardless of whether any data is persisted or not. – TechZen Sep 02 '11 at 22:41
  • 6
    @TechZen - Core Data is what many developers use to manage their persistent data, including _both_ modeling and storage/persistence. It's primary function is to accommodate that use-case. I don't think all the hand-waving about "it's not actually meant to do that" is appropriate. Regardless of what it's meant to do, that's how people use it. And if it's poorly designed and not-performant in certain iterations of that use-case, then that's a legitimate problem with Core Data. If Core Data supports SQLite persistence, then its SQLite persistence must be efficient. – aroth Mar 24 '14 at 01:08
  • @aroth - Core Data is complete model stack, including persistence. SQL is just persistence. Saying that CD has poor SQL is to disregard the rest of the stack, all of which you must manually create if you have all but the simplest index card type data model. If you think of Core Data as a lightweight wrapper around SQL then you don't understand it and, no, you won't use it efficiently. – TechZen May 01 '14 at 02:25
  • @aroth - It's really not acceptable to complain that a screwdriver does not work as well as a hammer nor to criticize the makers of screwdrivers for not making them better hammers. People need to learn the craft, study the API and use the right tool for the right job instead of always reaching for a hammer because that's what they've always used. – TechZen May 01 '14 at 02:29
  • 6
    @TechZen - Except you don't see many screwdriver manufacturers saying "by the way, our screwdriver supports hammering nails". But you _do_ see the maker of Core Data claiming to support SQLite persistence. If a screwdriver maker says "you can hammer nails with it", then the screwdriver had better be able to hammer nails _effectively_. And if Apple says "Core Data supports SQLite as a store type" then Core Data's SQLite implementation _must_ be efficient, correct, and scalable. Else Apple should just rescind support for SQLite storage since it's vaporous anyways. Do it right or not at all. – aroth May 01 '14 at 03:30
  • 1
    This is such a bad and patronizing answer. A good programmer will always look into what's under the hood, and if they can tweak that to make sure that things work better, then why not? That's like saying "you don't need to learn about memory management, we have reference counting." Nonsense. This question is very legitimate and your answer is just bad. – user884248 Aug 23 '16 at 07:11
  • 1
    I agree with this answer because a good programmer would learn a framework rather than wrap it into their way of thinking. Which unfortunately is harder than it sounds due to Apple not great with examples. The inheritance feature is designed to allow you to receive multiple entities in one fetch, e.g. in a fetched results controller, so a table can show different kinds of data in different cells, within in sections. They use a trick with a sort order param. So you should be modelling your data by how it will be presented rather than from a traditional relational database viewpoint. – malhal Dec 05 '17 at 01:58
2

Seems it is an old question, but I still hope I can help others who have same issue.

I found a good answer from this URL: https://www.objc.io/issues/4-core-data/core-data-models-and-model-objects/#entity-hierarchy-vs-class-hierarchy.

In order to avoid the url become invalid in the future, I posted some important content here:

For example, we have authors and books which are inherited from BaseEntity. What we should do is designing Entities as they should be, not using inheritance.

Entity hierarchy            Class hierarchy
----------------            ---------------
 Authors  Books               BaseEntity
                               |      |
                            Authors  Books

The code should be like this:

@interface BaseEntity : NSManagedObject
    @property (nonatomic) int64_t identifier;
    @property (nonatomic, strong) NSDate *createdAt;
    @property (nonatomic, strong) NSDate *changedAt;
@end

@interface Author : BaseEntity
    // Author specific code...
@end

@interface Book : BaseEntity
   // Book specific code...
@end
Stone
  • 29
  • 2
  • So, in this example, if I was using the Core Data modeler and had an entity named `Store` with relationships to other entities, and `Store` conditionally wanted to use `Author` or `Book` as attributes (i.e., in some cases `Store` would have `Author` and in other cases it might only have `Book`), would I only add either to `Store` programmatically, and leave them out of `Store` in the modeler? Thanks! – Evan R Feb 06 '16 at 03:08
  • @EvanR: Sorry for late reply, but I am not very clear your question. Could you explain more? In my understanding, you mean there is an entity `Store`, which has a relationship `Book` or `Author`. Is that right? And your last sentence is a little confused, could you make it clear? – Stone Feb 15 '16 at 09:28