The performance of NSSortDescriptor?

坚强是说给别人听的谎言 提交于 2019-12-24 09:59:38

问题


I have a SQLite backed database of roughly 4000 rows, connected to Core Data. The model is a simple overview -> detail model. Each overview (with title and subtitle) has a relationship to a detail, which contains detailed information. To view this data I have implemented a UITableView with a NSFetchedRequestController.

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;`

I have implemented everything and it works, but it works slowly. Specifically I'm concerned with the application launch.

This is the query that slows things down on launch time (SQL debug flag in XCode):

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. 

This happens immediately after performFetch is executed. Why does Core Data feel the need to get and sort all 4302 rows of my database? If I set the setLimit to a small value, say 20, of course everything works extremely fast, but I only get 20 results displayed. On the other hand, I now have setBatchSize, which works great, and I can see the SELECT statements in the debug console, as I scroll the table view. But it still sorts 4302 rows at launch, which I feel is unnecessarily slowing down app launch time.

I intend to implement a normalized string sorting and a caseInsensitiveNumericCompare selector in NSSortDescriptor, as per Apple's WWDC 2010 sample code, but it seems to me I'm missing something simple here.

Update:

Seems that I can't use a custom selector caseInsensitiveNumericCompare: with NSSortDescriptor, since I am using SQLite as the database. I really don't see what more I can do, to speed this up. Maybe SQLite will sort faster with shortened and normalized string, this is what I'm trying next.

Update 2:

With normalized string (no other letters or symbols except A-Z and 0-9), the launch time is down to about 0.7s. Not a big reduction. The last thing I'm trying is presorting the database and then assigning incremental ids to the rows. In NSSortDescriptor I will then sort by this numerical id. According to my SQL tests, it should be roughly 7x faster.


回答1:


I solved my own problem. This is just a reminder for anyone who might run into similar issues. The error I made was not creating indexes for the required fields on the database side. I just clicked the "indexed" option in my model in XCode. Apparently this DOES NOT create any indexes, if you have supplied the .sqlite file yourself.

After a curious launch case, where Core Data decided to create the database for me, I saw these SQL sentences executed:

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)

After I replicated these indexes on my own database, things have sped up considerably:

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.

I'm extremely happy with these numbers. But since I've now presorted my database, I can use a number for NSSortDescriptor. This brings me down to:

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.

So a little under 9 hundredths of a second, down from 9 tenths of a second.



来源:https://stackoverflow.com/questions/7697771/the-performance-of-nssortdescriptor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!