Возможны ли сложные индексы при использовании Core Data? - PullRequest
9 голосов
/ 20 ноября 2011

Я работаю над обучающим приложением в стиле флеш-карты для iOS, которое при загрузке должно получить кучу данных из Core Data.Но данные, которые мне нужны, представляют собой довольно специфическое подмножество сущности, основанное на пользовательских настройках, поэтому существует несколько предикатов, связанных с проверкой эквивалентности.Я считаю, что эти выборки очень медленные, и, основываясь на исследовании SQLite, я думаю, что индекс будет хорошим выбором здесь.

Теперь я понимаю (в основном из прочтения других вопросов о стековом потоке), что SQLite и CoreДанные - это две разные, в основном ортогональные вещи, которые не следует путать.Но я также понимаю, что вы должны работать с Core Data, чтобы выполнять какую-либо работу с базой данных и настраивать ее;Вы не должны пытаться обходить и работать напрямую с SQLite при оптимизации или проектировании постоянства объектов в вашем приложении.

Но единственное, что я могу найти для индексов в Базовых данных - это один «индексированный» флажок для каждого атрибутав модели.И это просто не та оптимизация, которую я ищу.

Вот запрос на выборку, в настоящее время:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"SKUserItem" inManagedObjectContext:context];
fetchRequest.entity = entity;

NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"next" ascending:YES] autorelease];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

NSMutableArray *predicates = [NSMutableArray arrayWithCapacity:6];
[predicates addObject:[NSPredicate predicateWithFormat:@"next < %f", now() + (60.0*60.0*24.0)]];
[predicates addObject:[NSPredicate predicateWithFormat:@"next > %f", nextOffset]];
[predicates addObject:[NSPredicate predicateWithFormat:@"user == %@", user]];
[predicates addObject:[NSPredicate predicateWithFormat:@"langRaw == %d", lang]];

NSArray *stylePredicates = [NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"styleRaw == %d", SK_SIMP_AND_TRAD], [NSPredicate predicateWithFormat:@"styleRaw == %d", self.style], nil];
[predicates addObject:[NSCompoundPredicate orPredicateWithSubpredicates:stylePredicates]];

if([self.parts count] == 4 || (self.lang == SK_JA && [self.parts count] == 3))
    ;  // don't have to filter by parts; they're studying all of them
else {
    NSMutableArray *partPredicates = [NSMutableArray arrayWithCapacity:[self.parts count]];
    for(NSString *part in self.parts)
        [partPredicates addObject:[NSPredicate predicateWithFormat:@"partRaw == %d", partCode(part)]];
    [predicates addObject:[NSCompoundPredicate orPredicateWithSubpredicates:partPredicates]];
}

NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
fetchRequest.predicate = compoundPredicate;

Так что, по сути, эта выборка сортируется по следующему (времякогда задан данный элемент) и фильтр по имени пользователя, изучаемому языку, изучаемому стилю (на китайском языке это упрощенный и традиционный) и изучаемым частям (написание, тональность, чтение или определение), и выборка только в пределах "следующий "ассортимент.Вот краткий список того, чему я научился, настраивая и манипулируя этим:

  1. Он всегда сканирует всю таблицу, или кажется.Несмотря на то, что next индексируется, даже если я заставлю его искать диапазон, который, как я знаю, ничего не даст, для извлечения все равно потребуется несколько секунд.
  2. Предикаты, любое количество предикатов, замедляют процесс.Если я удаляю некоторые, но не все, это примерно так же медленно.Если я удаляю все предикаты (таким образом нарушая приложение), то это происходит намного быстрее.
  3. Скорость сильно зависит от общего количества пользовательских элементов в таблице.Чем больше предметов, тем медленнее.У некоторых людей может быть десятки тысяч предметов, и тогда эта выборка может занять до 10 секунд.Это приводит к неловким паузам в моем приложении.
  4. Верхняя граница следующего значения была добавлена ​​не потому, что она нам нужна, а потому, что она немного ускоряет выборку.
  5. Наличиезапрос возвращает подмножество свойств в словаре (а не весь управляемый объект), а выборка лениво выполняется быстрее, но все же не достаточно быстро.

Я пришел из Google App Engine здесьЯ привык к индексам, которые они там предоставляют.По сути, я хочу такой индекс, но применяется к SQLite через Core Data.Я нашел информацию о добавлении индексов в SQLite, какой я хотел бы, но, выполняя такого рода индексацию с помощью Core Data, я не могу найти никакой информации об этом.

Ответы [ 2 ]

18 голосов
/ 28 декабря 2011

Вам нужен составной индекс , который Core Data поддерживает в iOS 5.0 и более поздних версиях.

Вы можете настроить его в Xcode: инспектор Entity имеет Indexes раздел, или если вы создаете NSEntityDescription в коде, используйте -setCompoundIndexes:.

Если вы используете Xcode, вы добавили бы строку в Индекс раздел, в котором написано

next,user,langRaw

Таким образом, SQL может использовать индекс для вашего запроса.

2 голосов
/ 20 ноября 2011

Базовые данные имеют SQL-сервер. Таким образом, вы будете иметь все данные в одной таблице (часть одной сущности), и для поиска искомых объектов потребуется поиск по всем строкам, как вы говорите.

В вашей модели данных вам нужно разбить некоторые атрибуты, которые вы ищете, на другие объекты. Постарайтесь сделать его более ориентированным на объект и подумайте, что вы будете искать.

например. есть объект для пользователя, языка и, возможно, один для уроков или что-то еще, основанное на времени, это то, что вы ищете.

Сущность Урока имеет отношение ко многим для Языка и одно отношение к пользователю. (или многим, если более одного пользователя посещают занятия)

Затем, чтобы найти данные пользователя, вы выбираете этого пользователя и исследуете его свойство Language или Lessons, чтобы узнать больше.

Чтобы найти список пользователей, изучающих язык, выберите нужную вам языковую сущность и изучите свойство пользователей.

...