获取请求性能问题

时间:2010-12-21 09:57:37

标签: iphone performance sqlite core-data

在使用大约查询sqlite数据库时,我遇到了一些严重的性能问题。 25k行。 我想要做的是以下内容:当用户在文本字段中键入内容时,我想在tableview中为他提供自动完成建议,这是键盘的inputAccessoryView。每次他输入一个新角色时,都会有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 :(得分:0)

我想我可能已经发现了它。

您执行查询以获取实体并将其放入结果数组中。这是查询号1,它已经优化好了(假设没有连接等,但它看起来不像)

然后,您将浏览所有结果以删除结果中已有的重复项。这意味着您执行新查询以获取每个Station NSManagedObject。如果你想避免重复,你必须在不调用objectWithID的情况下这样做,因为这将是来自CoreData的对象。

最坏的情况是,要获得20个站点的结果,您需要21个查询。不好。

由于sqlite3是单线程的,为什么不只是创建一个大的谓词而不是4个较小的谓词 - 然后你可以删除谓词中的重复项,并且在绘制之前不需要遍历数组车站的表格视图。

我在查找之前遇到过这个问题,必须通过在数据库中创建一个单独的表来解决它。在您的情况下,该表(称为station_search)将仅包含站名(当然将被索引)和stationId。然后我在这个表上进行搜索(这会很快,因为它没有很多数据可以搜索)。

一旦我得到了我的结果,我只是在我需要时才使用stationId从主站表获取本站即我在表中绘制单元格。

我也可以使用NSFetchedResultsController将结果批量处理。

这已经变得有点絮絮叨叨 - 如果你有什么问题可以问一下!

希望它有所帮助,

萨姆

答案 1 :(得分:0)

好的,我终于明白了。用

替换了LIKE查询
reducedTownName >= %@ AND reducedTownName <= %@

其中第一个参数是搜索词,第二个参数又是搜索词,除了最后一个字母被下一个字母替换,例如。

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

这非常快,给了我想要的结果。我也可以在主线程中移动查询,这给了我额外的性能提升。

问候

萨姆