我的iPhone应用程序有一个实体Words
,其属性为word
,length
和language
。两者都被编入索引:
我将cdatamodel和数据库复制到一个单独的导入器应用程序,在该应用程序中预先填充了大约400,000个不同语言的单词。我通过查看SQLite文件验证了导入,然后将预先填充的数据库复制回iPhone项目。
首先,我认为(简单)谓词是问题所在。但即使从获取请求中删除谓词,也需要很长时间才能执行:
2011-09-01 09:26:38.945 MyApp[3474:3c07] Start
2011-09-01 09:26:58.120 MyApp[3474:3c07] End
以下是我的代码:
// Get word
NSLog(@"Start");
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Words" inManagedObjectContext:appDelegate.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [appDelegate.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
//... error handling code
}
[fetchRequest release];
NSLog(@"End");
return fetchedObjects;
数据库中的条目数是否是Core Data的问题?
修改:
正如gcbrueckmann和jrturton指出的那样,设置fetchBatchSize
是一个很好的观点。但是获取时间仍然不尽如人意:
带谓词集的2秒:
NSPredicate * predicate = [NSPredicate predicateWithFormat:@“length ==%d AND language BEGINSWITH%@”,wordLength,lng]; [fetchRequest setPredicate:predicate];
设置批量大小时为7秒:
[fetchRequest setFetchBatchSize:1];
设置谓词和批量大小的时间为1秒
还有另一个瓶颈吗?
答案 0 :(得分:12)
由于您没有以任何方式限制结果集,一次取出400,000个对象肯定会成为Core Data的负担。有几种方法可以提高性能:
更改获取请求的fetchBatchSize
会限制fetch一次保留在内存中的对象数。此功能对您的应用程序完全透明,因此绝对值得一试。
如果您不需要完全成熟的对象,可以考虑将获取请求的resultType
更改为更合适的值。特别是如果您只对某个对象的某些值感兴趣,那么使用NSDictionaryResultType
是一个好主意。
如果您想自己管理批处理,最后fetchLimit
和fetchOffset
属性允许您限制结果范围。如果您对每个结果对象的处理使用大量内存,这是一个好主意,因为您可以将每个批处理包装在NSAutoreleasePool
中(只是不要试图为每个结果对象创建一个自动释放池)。
我想1秒。可能只是在你的情况下快速 - 即使你求助于一个普通的Sqlite数据库。我能想到的唯一进一步优化是每种语言使用一个表(而不是将所有语言中的单词放入单个表中)。当然,这只适用于Sqlite,除非您为所有语言定义单独的实体,即。即按原样取出Words
实体并将其抽象化。然后添加像EnglishWord
等子单元。来自不同实体的对象存储在单独的表中。因此,结合fetchBatchSize
和predicate
参数,这应该与Sqlite方法类似地执行,并为所有语言使用单独的表。
答案 1 :(得分:2)
你正在做BEGINSWITH - 这不是一个非常快速的操作!但是,语言数量有限,所以emum可能会有所帮助。
有一个language_id字段,它是一个索引整数,并在谓词中使用它。您仍然可以存储语言名称并将其作为获取对象的一部分返回,只是不要搜索它:)
PS您可以通过添加'-com.apple.CoreData.SQLDebug 1'作为启动时传递的参数(在您的Scheme中配置它)来启用SQL调试 - 这可能有助于您了解SQL在幕后执行的操作。
(有关详细信息,请参阅this question)
答案 2 :(得分:1)
这会将你的完整400k数据库提取到内存中,看起来确实很多。你可以调查NSFetchRequest的
setFetchBatchSize
方法,在假设您不需要在第一个实例中从存储中提取每个返回的对象时,停止框架为获取请求中的所有内容返回完整对象。