在使用大约查询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。
有人在此代码中看到任何性能杀手,或者对我有其他建议吗?
答案 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'
这非常快,给了我想要的结果。我也可以在主线程中移动查询,这给了我额外的性能提升。
问候
萨姆