Производительность CoreData: предикат отношений больше ко многим

Используя хранилище данных SQL, у меня есть такая модель:

Категория ‹-->> Товар

Коллекция ‹-->> Предмет

Бренд ‹-->> Товар

Каждая левая сущность имеет отношение ко многим под названием items с сущностью Item. Каждый из них является обратным отношениям к одному элементу категория, коллекция и бренд соответственно.

Я хочу получить все объекты бренда с хотя бы одним элементом, связанным с конкретной коллекцией И категорией. Говоря естественным языком, мне нужны все марки предметов с определенной категорией и определенной коллекцией.

Учитывая объекты Category * myCategory и Collection * myCollection, я использую для построения предиката сущности Brand в Сюда:

NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"(ANY items.category == %@) AND (ANY items.collection == %@)",myCategory,myCollection]; 

И я получаю правильные результаты. Проблема в производительности. Слишком медленно! И я упростил вопрос на три уровня! Давайте рассмотрим четыре уровня в многоуровневом каталоге iOS: приложение показывает доступные категории, пользователь выбирает категорию, приложение показывает коллекции в этой категории, пользователь выбирает коллекцию, приложение показывает бренды в этой коллекции (и уже выбранную категорию), пользователь выберите бренд, приложение покажет, например, материалы этого бренда, коллекции и категории ...

Честно говоря, я использую NSCompoundPredicate, чтобы вставлять субпредикаты AND при каждом выборе пользователя, динамически создавая последний предикат. Но это не имеет значения для цели вопроса.

В хранилище данных sql находится более 30 000 (30 КБ) объектов сущности Item, и использование И между элементами выполняется очень медленно (я заметил задержку в 7–10 секунд. чтобы показать бренды в приведенном выше примере).

Я бы попробовал:

- удалить связи элементы из категорий, коллекций и брендов.

-в сущности Item замените отношения category, collection и brand на выбранные свойства в таких атрибутах, как «category_id», «collection_id» и «brand_id». ".

-использовать ключевой путь или предикаты для получения брендов без использования отношений ко многим.

Прежде чем я начну уничтожать и переделывать всю работу за последние 6 месяцев, у вас есть какие-нибудь предложения? :)

Спасибо!


person Donnit    schedule 25.10.2011    source источник


Ответы (1)


Измените логику того, что вы ищете.

Вы не ищете Бренд с определенной категорией и определенной коллекцией; вы ищете объект Item с категорией X и набором Y. Когда у вас есть Item, вы можете спросить его бренд:

id myCategory = ...;
id myCollection = ...;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Item"];
[request setPredicate:[NSPredicate predicateWithFormat:@"category == %@ && collection == %@", myCategory, myCollection]];

NSError *error = nil;
NSArray *itemArray = [moc executeFetchRequest:request error:&error];
NSAssert2(!error || itemArray, @"Error fetching items: %@\n%@", [error localizedDescription], [error userInfo]);

NSArray *brands = [itemArray valueForKey:@"brand"];
return brands;

Обновлять

Предмет - это объект на другом конце отношения, как и в вашем вопросе. -valueForKey: пройдется по массиву элементов, получит сущность Brand на другом конце отношения и вернет вам массив Brand. Вам не нужно ничего добавлять, даже свойство, поскольку доступ к нему будет осуществляться через KVC, и он будет «просто работать».

Это даст вам наиболее эффективный поиск в зависимости от ваших требований. Поскольку Item находится на стороне многих каждой из этих отношений, он будет содержать внешние ключи, и поэтому SQL не нужно будет пересекать границы таблицы и, следовательно, должен быть очень быстрым.

Единственный другой вариант, и я его не рекомендую, но вы можете поиграть с наборами из категорий и коллекций и получить объединение из изменяемого набора. Каждый раз, когда я экспериментировал с этим направлением, это было медленнее, чем обращение к базе данных. На мой взгляд, такую ​​логику лучше всего реализовать на уровне базы данных.

person Marcus S. Zarra    schedule 26.10.2011
comment
Это то, что я пробовал, когда прочитал ваш ответ! Эта логика более эффективна, но я думаю, что ее еще можно оптимизировать. Учтите, что: 1) существует более 30 тыс. Сущностей элементов, запрос на выборку занимает некоторое время, например, 1 секунда вместо 7 секунд при использовании отношений ко многим, но это все еще длительное время ожидания для взаимодействия с пользователем (пользователь пытается повторить попытку) 2 ) Когда вы используете [itemArray valueForKey: @brand], как вы моделируете бренд в сущности Item? Как свойство, отношение или полученная собственность? В первом случае мне понадобится еще n запросов на выборку ... - person Donnit; 27.10.2011