SQL 与核心数据的真实世界性能:需要透视和可能的特定修复
Posted
技术标签:
【中文标题】SQL 与核心数据的真实世界性能:需要透视和可能的特定修复【英文标题】:Real World Peformance of SQL vs Core Data: Need Perspective and Perhaps Specific Fixes 【发布时间】:2012-10-27 16:40:58 【问题描述】:我有一个文字游戏应用程序,它可以访问单词和线索列表,大约有 10 万个条目。数据库只被访问,从不改变。我使用 SQL 方法构建了应用程序,它在 ios 6 上运行良好,但在 iOS 5 上从数据库中获取新线索的时间非常慢:
iOS 5,使用 SQL 从 100K 中获取一条记录,大约需要 12 秒。 iOS 6,使用 SQL 从 100K 中获取一条记录,需要 大约 700-1000 毫秒。这两个都在 32 GB iPod Touch 上。
鉴于这种性能,我使用 Core Data 制作了一个版本。我的方法通过首先计算适合查询的记录,然后随机选择一个来获得随机数据库条目。代码如下。我读到的所有内容都表明 Core Data 会更快:
iOS 5,计数记录大约需要 4 秒,并检索其中之一 这些记录大约需要 50 - 1500 毫秒。总时间约为 5 秒。 iOS 6,计数记录需要 2 秒多一点,检索 其中一项记录大约需要 300-500 毫秒。总共大约 3 秒。因此,与 SQL 相比,Core Data 在 iOS 5 上更快,但在 iOS 6 上更慢。就我而言,无论哪种方式,性能都太慢了。我知道开销来自下面给出的方法(对于核心数据版本)。所以,两个问题:
-
有关此问题的任何一般性建议,以了解它并提高性能?
具体来说,下面附加的核心数据代码呢:我做了什么愚蠢的事情来减慢它的速度吗?还是我应该添加其他东西来加快速度?这是我第一次尝试 Core Data。
谢谢。
- (NSArray *) randomClue
NSManagedObjectContext* context = [self managedObjectContext];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"A"];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:@"WL28"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [self createSearchQuery];
[fetchRequest setPredicate:predicate];
NSError *error;
NSDate *date1 = [NSDate date];
NSString *timeString1 = [formatter stringFromDate:date1];
int resCount = [context countForFetchRequest:fetchRequest
error:&error];
NSDate *date2 = [NSDate date];
NSString *timeString2 = [formatter stringFromDate:date2];
int t1 = [timeString1 intValue];
int t2 = [timeString2 intValue];
int d1 = t2-t1;
NSLog(@"randomClue:");
NSLog(@" Time to count array entries: %i", d1);
int ranNum = arc4random_uniform(resCount-1);
int ranNum2 = ranNum + 1;
// Now we fetch just one answer object, not a whole database or even a piece of it!
[fetchRequest setReturnsObjectsAsFaults:YES];
[fetchRequest setPropertiesToFetch:nil];
[fetchRequest setFetchLimit:1];
[fetchRequest setFetchOffset:ranNum2];
NSDate *date3 = [NSDate date];
NSString *timeString3 = [formatter stringFromDate:date3];
self.wl28 = [context executeFetchRequest:fetchRequest error:&error];
NSDate *date4 = [NSDate date];
NSString *timeString4 = [formatter stringFromDate:date4];
int t3 = [timeString3 intValue];
int t4 = [timeString4 intValue];
int d2 = t4-t3;
NSLog(@" Time to retrieve one entry: %i", d2);
return self.wl28;
编辑:在下方添加 createSearchQuery
- (NSPredicate *)createSearchQuery
NSMutableArray *pD = [[GameData gameData].curData valueForKey:@"persData"];
NSNumber *currMin = [pD objectAtIndex:0];
NSNumber *currMax = [pD objectAtIndex:1];
NSNumber *dicNo = [pD objectAtIndex:2];
NSString *dict = nil;
if ([dicNo intValue] == 0) dict = @"TWL";
if ([dicNo intValue] == 1) dict = @"LWL";
NSPredicate *dictPred = [NSPredicate predicateWithFormat:@"dict == %@", dict];
NSPredicate *lowNoCPred = [NSPredicate predicateWithFormat:@"noC >= %@", currMin];
NSPredicate *highNoCPred = [NSPredicate predicateWithFormat:@"noC <= %@", currMax];
NSPredicate *query = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray
arrayWithObjects:dictPred, lowNoCPred, highNoCPred,nil]];
NSLog(@"%@", query);
return query;
【问题讨论】:
如果数据库是只读的,为什么每次都统计条目? 根据用户设置存在子集,这反过来会影响查询。最大的子集约为 70K,这就是性能数据的基础。这些数量不是无限的,所以我可能会预先计算这些以节省一些时间。 如果你告诉我们createSearchQuery
方法会更容易。
@TomaszZabłocki 感谢您查看此内容:我将代码添加到原始帖子中。
【参考方案1】:
您可以尝试将索引添加到实体内的 noC 和/或 dict 属性。它可能会加快您的查询时间。
【讨论】:
你能指点我一些文档吗?我已经看到过索引核心数据结构的提及,但是在NSPredicate
或核心数据编程指南的文档中都没有出现索引这个词。
OK 在 Xcode 中打开 xcdatamodel,切换到网格编辑器样式,然后选择您的实体,然后属性 noC 或 dict。在右侧选择它后,您将拥有 Data Model Inspector。有属性索引所以只需检查它。 Wikipedia - about index
很棒的电话!这将在 iOS 6 上检索单个条目的时间减少到大约 50-200 毫秒。计算条目的时间几乎没有变化。关于加快速度的任何建议?如果需要,我想我可以硬连线 dict
和 noC
的每个可能组合的条目数,这将用快速查找代替该步骤。
另一个提示:您可以使用 NSFetchedResultsController 只查询一次并保留它直到您的应用程序终止。这样你就可以从 fetchedObjects 属性中选择随机对象,将两个调用的时间减少到 ~0。
再次感谢您。我将研究 NSFetechedResultsController,或者我可以做类似的事情:当用户更改设置时,从主数据库中提取的线索子集很少更改。所以我可以把它放在一个数组中很长一段时间,然后随机抓取它。谢谢你的帮助!接受答案。以上是关于SQL 与核心数据的真实世界性能:需要透视和可能的特定修复的主要内容,如果未能解决你的问题,请参考以下文章
性能测试的思维没打开,很多同学可能一开始就错了(内附真实项目性能测试报告)