我有一个大约4000行的SQLite支持的数据库,已连接到Core Data。该模型是一个简单的概述->详细模型。每个概述(包括标题和副标题)都与一个包含详细信息的细节相关。为了查看此数据,我实现了一个带有NSFetchedRequestController的UITableView。

NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"registered_name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sort];

NSPredicate *filterPredicate = nil;
NSString *sectionName = nil;
NSString *cacheName = nil;

NSFetchedResultsController *aFetchedResultsController = nil;
aFetchedResultsController.delegate = self;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

[fetchRequest setFetchBatchSize:20];
[fetchRequest setSortDescriptors:sortDescriptors];

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Info" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

[fetchRequest setPredicate:filterPredicate];
aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:sectionName cacheName:cacheName];

NSError *error = nil;
if (![aFetchedResultsController performFetch:&error])
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  abort();
}

[fetchRequest release];
[sort release];
return aFetchedResultsController;`


我已经实现了所有内容,并且可以运行,但是运行缓慢。我特别关注应用程序的启动。

这是使启动时间变慢的查询(XCode中的SQL调试标志):

CoreData: sql: SELECT 0, t0.Z_PK FROM ZINFO t0 ORDER BY t0.ZREGISTERED_NAME
CoreData: annotation: sql connection fetch time: 0.8773s
CoreData: annotation: total fetch execution time: 0.8976s for 4302 rows.


这在执行performFetch之后立即发生。为什么Core Data感到需要获取和排序数据库的所有4302行?如果我将setLimit设置为一个较小的值,例如20,那么当然一切都会非常快,但是我只会显示20个结果。另一方面,我现在有了setBatchSize,它运行良好,并且在滚动表视图时可以在调试控制台中看到SELECT语句。但是它在启动时仍会排序4302行,我认为这不必要地拖慢了应用启动时间。

根据苹果的WWDC 2010示例代码,我打算在NSSortDescriptor中实现规范化的字符串排序和caseInsensitiveNumericCompare选择器,但在我看来,这里似乎缺少一些简单的东西。

更新:

似乎我不能将自定义选择器caseInsensitiveNumericCompare:与NSSortDescriptor一起使用,因为我将SQLite用作数据库。我真的不知道我能做些什么来加快速度。也许SQLite使用缩短和规范化的字符串可以更快地排序,这就是我接下来要尝试的。

更新2:

使用归一化的字符串(除了A-Z和0-9之外没有其他字母或符号),启动时间可缩短至约0.7s。没有大的减少。我要尝试的最后一件事是对数据库进行预排序,然后将增量ID分配给行。然后在NSSortDescriptor中,我将按此数字ID进行排序。根据我的SQL测试,它应该快7倍左右。

最佳答案

我解决了自己的问题。这只是对任何可能遇到类似问题的人的提醒。我犯的错误是没有在数据库端为必填字段创建索引。我只是在XCode中单击模型中的“索引”选项。显然,如果您自己提供了.sqlite文件,则此操作不会创建任何索引。

在一个奇怪的启动案例之后,Core Data决定为我创建数据库,我看到执行了以下SQL语句:

2011-10-08 19:49:40.572 App[1717:307] CoreData: sql: CREATE INDEX ZINFO_ZREGISTERED_NAME_INDEX ON ZINFO (ZREGISTERED_NAME)
2011-10-08 19:49:40.586 App[1717:307] CoreData: sql: CREATE INDEX ZINFO_ZFIRSTLETTER_INDEX ON ZINFO (ZFIRSTLETTER)
2011-10-08 19:49:40.598 App[1717:307] CoreData: sql: CREATE INDEX ZINFO_ZNAME_INDEX ON ZINFO (ZNAME)
2011-10-08 19:49:40.610 App[1717:307] CoreData: sql: CREATE INDEX ZINFO_ZN_SL_NAME_INDEX ON ZINFO (ZN_SL_NAME)
2011-10-08 19:49:40.622 App[1717:307] CoreData: sql: CREATE INDEX ZINFO_ZN_REGISTERED_NAME_INDEX ON ZINFO (ZN_REGISTERED_NAME)
2011-10-08 19:49:40.635 App[1717:307] CoreData: sql: CREATE INDEX ZINFO_ZDETAILS_INDEX ON ZINFO (ZDETAILS)


在将这些索引复制到自己的数据库中之后,情况大大加快了:

CoreData: sql: SELECT 0, t0.Z_PK FROM ZINFO t0 ORDER BY t0.ZREGISTERED_NAME
CoreData: annotation: sql connection fetch time: 0.1315s
CoreData: annotation: total fetch execution time: 0.1568s for 4161 rows.


我对这些数字感到非常满意。但是,由于现在已经对数据库进行了预排序,因此可以为NSSortDescriptor使用一个数字。这使我归结为:

CoreData: sql: SELECT 0, t0.Z_PK FROM ZINFO t0 ORDER BY t0.ZID
CoreData: annotation: sql connection fetch time: 0.0677s
CoreData: annotation: total fetch execution time: 0.0890s for 4161 rows.


从9分之1秒降低到9分之1秒以下。

关于ios - NSSortDescriptor的性能?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7697771/

10-11 14:03