Производительность CoreData: предикат от множества отношений - PullRequest
2 голосов
/ 26 октября 2011

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

Категория <- >> Пункт

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

Марка <- >> Товар

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

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

Учитывая объекты Категория * myCategory и Коллекция * myCollection , я использую для создания предиката сущности Brand в этом способ:

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

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

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

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

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

-remove items Отношения из категории, коллекции и торговой марки

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

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

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

Спасибо!

1 Ответ

2 голосов
/ 26 октября 2011

Обратная логика того, что вы ищете.

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

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: будет проходить через множество предметов, получит сущность Бренда на другом конце отношений и вернет вам массив Бренда. Вам не нужно ничего добавлять, даже свойство, так как оно будет доступно через KVC и будет «просто работать».

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

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

...