Возможны ли сложные индексы при использовании Core Data?

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

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

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

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

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;

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

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

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

9
задан scott_at_skritter 19 November 2011 в 22:13
поделиться