проблемы с производительностью запросов - PullRequest
0 голосов
/ 21 декабря 2010

У меня серьезные проблемы с производительностью при запросе базы данных sqlite с прибл. 25 тыс строк Я хочу сделать следующее: когда пользователь вводит что-то в текстовое поле, я хочу дать ему предложения по автозаполнению в виде таблицы, которая является входным представлением клавиатуры. Каждый раз, когда он вводит нового персонажа, 4 новых запроса отправляются на поиск соответствующих предложений. Я делаю это в отдельном потоке, используя GCD и блоки. Однако производительность слишком низкая. Вот код для одного запроса:

- (void) queryDatabase:(NSString *) searchString
{   
[self.fetchedResults removeAllObjects];

dispatch_queue_t fetchQueue = dispatch_queue_create("Fetch Queue", NULL);

dispatch_async(fetchQueue,^{
    NSError *error = nil;
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
    context.undoManager = nil;
    [context setPersistentStoreCoordinator: self.persistentStoreCoordinator];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"reducedTownName like %@", [searchString stringByAppendingString:@"*"]];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    request.entity = [NSEntityDescription entityForName:@"Station" inManagedObjectContext:context];
    request.fetchLimit = 20;
    [request setIncludesPropertyValues:NO];
    request.predicate = predicate;
    request.resultType = NSManagedObjectIDResultType;

    NSArray *results = [context executeFetchRequest:request error:&error];
    NSEnumerator *e = [results objectEnumerator];
    NSManagedObjectID *objectId = nil;

    while (objectId = [e nextObject]) 
    {
        Station *station = (Station *) [self.managedObjectContext objectWithID:objectId];
        if ( ![self.fetchedResults containsObject:station])
            [self.fetchedResults addObject:station];
    }       

    dispatch_async(dispatch_get_main_queue(),^{
        [self.tableView reloadData];
    });
    [request release];
    [context release];
});
    //do 3 more queries similar to the first (only predicate changes)
    dispatch_release(fetchQueue);
}

Я использую NSArray (fetchedResults) для хранения возвращенных сущностей и обновляю tableView данными из этого массива.

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

Ответы [ 2 ]

0 голосов
/ 28 декабря 2010

Хорошо, я наконец понял. Заменен запрос LIKE на

reducedTownName >= %@ AND reducedTownName <= %@

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

reducedTownName >= 'oak' AND reducedTownName <= 'oal'

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

Привет

Sam

0 голосов
/ 21 декабря 2010

Я думаю, я мог это заметить.

Вы выполняете свой запрос, чтобы получить объекты и поместить их в массив результатов.Это запрос номер 1, и он хорошо оптимизирован (при условии, что нет никаких объединений и т. Д., Но он не выглядит таковым)

Затем вы просматриваете все результаты, чтобы удалить дубликаты, которые уже есть в ваших результатах.Это означает, что вы выполняете новый запрос для получения каждого Station NSManagedObject.Если вы хотите избежать дубликатов, вам придется делать это без вызова objectWithID, поскольку это приведет к извлечению объекта из CoreData.

В худшем случае, чтобы получить результаты по 20 станциям, вам нужно 21 запрос.Не хорошо.

Поскольку sqlite3 является однопоточным, почему бы вам просто не сделать большой предикат вместо 4 меньших - тогда вы можете удалить свои дубликаты в предикате, и вам не нужно будет проходить через массивпока не пришло время нарисовать ячейку табличного представления этой станции.

У меня раньше была эта проблема с поисками, и мне пришлось ее решать, создавая отдельную таблицу в базе данных.В вашем случае эта таблица (называемая station_search) будет содержать только название станции (которая, конечно, будет проиндексирована) и идентификатор станции.Затем я выполняю поиск по этой таблице (что будет быстро, потому что в ней не так много данных для поиска).

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

Я также могу использовать NSFetchedResultsController , чтобы объединить мои результаты.

Это превратилось в небольшую шумиху - если у вас есть какие-либо вопросы, просто задавайте!

Надеюсь, это поможет,

Сэм

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...