Базовые данные: загрузка элементов происходит медленно с предикатом - PullRequest
0 голосов
/ 30 июля 2011

Для приложения iPhone я настроил модель данных для Core Data.Он содержит одну сущность Words, а его атрибуты language : String, length : Integer16 и word : String.

. Я предварительно заполнил базу данных SQLite своей модели списком слов (200 тыс. Элементов), написав отдельное приложение для iPhone с помощьюидентичная модель данных и копирование заполненной базы данных в основное приложение.

Теперь, используя NSFetchedRequest, я могу запрашивать управляемые объекты, как мне нравится, но результаты приходят медленно.Я использую следующий метод:

- (NSString *)getRandomWordLengthMin:(int)minLength max:(int)maxLength
{
    NSString *word = @"";

    MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Words"
                                              inManagedObjectContext:context];
    [fetchRequest setEntity:entity];

    NSString *predicateString = @"length >= %d AND length <= %d";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString,
                              minLength, maxLength];
    [fetchRequest setPredicate:predicate];

    NSError *error = nil;
    int entityCount = [context countForFetchRequest:fetchRequest error:&error];
    [fetchRequest setFetchLimit:1];
    if(entityCount != 0)
    {
        [fetchRequest setFetchOffset:arc4random()%entityCount];
    }

    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
    if([fetchedObjects count] != 0)
    {
        Words * test = [fetchedObjects objectAtIndex:0];
        word = [NSString stringWithFormat:@"%@", [test word]];
    }

    return word;
}

Используя редактор SQLite, я уже установил индекс вручную для столбца zLength, но это не принесло никакого ускорения.Где узкое место?

РЕДАКТИРОВАТЬ:

Я понял, что получение int entityCount = ... идет медленно.Но даже получить все объекты и затем выбрать одно случайное слово медленно:

Words * test = [fetchedObjects objectAtIndex:arc4random()%[fetchedObjects count]];

Ответы [ 2 ]

3 голосов
/ 30 июля 2011

Вы фактически запускаете здесь две выборки: одну для получения количества выборок, а другую - для выборки реального объекта. Это замедлит ход событий.

Ваш предикат "назад". Сложные предикаты оценивают первое выражение, например, length >= %d и затем оцените второе, например length <= %d только против результатов первого. Поэтому вы должны поставить тест, который удаляет большинство объектов в первую очередь. В этом случае length <= %d, вероятно, удаляет больше объектов, поэтому он должен стоять первым в предикате.

Поскольку на самом деле вам нужен не весь управляемый объект Words, а только строка word, вы можете установить тип возвращаемого значения NSDictionaryResultType, а затем задать для свойства выборку только атрибут word , Это значительно ускорит процесс.

Часть вашей проблемы здесь заключается в том, что Базовые Данные предназначены для управления графом структурированных объектов, и вы используете случайный / неструктурированный граф, поэтому вы сокращаете суть оптимизации Базовых Данных.

1 голос
/ 30 июля 2011

Не используйте редактор SQLite для редактирования резервного хранилища SQLite для хранилища Core Data.Внутренние элементы базы данных являются частными и могут быть изменены.

Вместо этого зайдите в редактор моделей в XCode и просто поставьте галочку на опции «indexed» для атрибута сущности, который вы хотите проиндексировать.

Не уверен, но, возможно, этот предикат легче оптимизировать:

NSString *predicateString = @"length BETWEEN (%d, %d)";
...