0

I am working on a project with the following many-to-many model:

Book: can have multiple tags (book.tags) Tag: can include a lot of books (tag.books)

i found that when a book is already in database and i just simply want to add a tag to that book by doing [bookMO addTagsObject:tag], i will get a fault in book.tags. using the instrument, i found the core data is trying to do "[NSObject(NSKeyValueObserver(Notification) willChangeValueForKey:withSetMutation:usingObjects]".

i also checked the actual sql getting executed and i found: annotation: to-many relationship fault "tags" for objectID 0x20140b00 fulfilled from database. and then a sql query that returns all the tags that contain this book. i found internally core data use a join table of Book and Tag. the primary key of that join table is simply a combination of book_id and tag_id. That joint table is not indexed. And to get all the tags that contain a book, it seems to be (i am not sure here) traversing all the rows in that joint table and therefore this operation is very expensive.

i think what is happening in my app now is, every time i want to add a tag to a book, i will have to do that linear scan in the joint table. The overall complexity is O(N^2) because each operation will do a linear scan in the join table. And I am having 10k books now and the performance is not so good..

is there any way i can avoid that tags fault triggered by kvo? or is there any way i can implement my own join table that can return the result in O(1) by indexing?

-Erben

thSoft
  • 21,755
  • 5
  • 88
  • 103
Erben Mo
  • 3,528
  • 3
  • 19
  • 32

1 Answers1

0

sorry for the delayed update.

Core data is just not good for many-to-many relationships as it doesn't create the index that I want.

I ended up creating a RleationManagedObject. which has a property "book" pointing to a BookManagedObject and a property "tag" pointing to a TagManagedObject. both property are indexed (very important, default core data is not indexing both properties).

Every time I need to add "tag_1" on "book_1", I search all the RelationManagedObject with "book_1" and "tag_1". if not found, I create this relationManagedObject. I can also create relationManagedObject with <"book_1", "tag2">, or <"book_2", "tag_1">, etc. Basically I am managing the relationship by myself.

so the gotcha is core data many-to-many relationship doesn't index properly.

Also, xcode can print out the sql that it executed. The first time you opened the app it will create those tables that you defined in core data. so you can see how CoreData Framework create the default "Relationship" table without indexing properly. and thats how I found the issue.

Erben Mo
  • 3,528
  • 3
  • 19
  • 32