简单的核心数据提取非常慢

时间:2011-09-01 07:50:50

标签: iphone performance core-data

我的iPhone应用程序有一个实体Words,其属性为wordlengthlanguage。两者都被编入索引: Entity and attributes

我将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秒

还有另一个瓶颈吗?

3 个答案:

答案 0 :(得分:12)

由于您没有以任何方式限制结果集,一次取出400,000个对象肯定会成为Core Data的负担。有几种方法可以提高性能:

更改获取请求的fetchBatchSize会限制fetch一次保留在内存中的对象数。此功能对您的应用程序完全透明,因此绝对值得一试。

如果您不需要完全成熟的对象,可以考虑将获取请求的resultType更改为更合适的值。特别是如果您只对某个对象的某些值感兴趣,那么使用NSDictionaryResultType是一个好主意。

如果您想自己管理批处理,最后fetchLimitfetchOffset属性允许您限制结果范围。如果您对每个结果对象的处理使用大量内存,这是一个好主意,因为您可以将每个批处理包装在NSAutoreleasePool中(只是不要试图为每个结果对象创建一个自动释放池)。

我想1秒。可能只是在你的情况下快速 - 即使你求助于一个普通的Sqlite数据库。我能想到的唯一进一步优化是每种语言使用一个表(而不是将所有语言中的单词放入单个表中)。当然,这只适用于Sqlite,除非您为所有语言定义单独的实体,即。即按原样取出Words实体并将其抽象化。然后添加像EnglishWord等子单元。来自不同实体的对象存储在单独的表中。因此,结合fetchBatchSizepredicate参数,这应该与Sqlite方法类似地执行,并为所有语言使用单独的表。

答案 1 :(得分:2)

你正在做BEGINSWITH - 这不是一个非常快速的操作!但是,语言数量有限,所以emum可能会有所帮助。

有一个language_id字段,它是一个索引整数,并在谓词中使用它。您仍然可以存储语言名称并将其作为获取对象的一部分返回,只是不要搜索它:)


PS您可以通过添加'-com.apple.CoreData.SQLDebug 1'作为启动时传递的参数(在您的Scheme中配置它)来启用SQL调试 - 这可能有助于您了解SQL在幕后执行的操作。

(有关详细信息,请参阅this question

答案 2 :(得分:1)

这会将你的完整400k数据库提取到内存中,看起来确实很多。你可以调查NSFetchRequest的

setFetchBatchSize

方法,在假设您不需要在第一个实例中从存储中提取每个返回的对象时,停止框架为获取请求中的所有内容返回完整对象。

相关问题