2011-09-01 53 views
7

我的iPhone应用程序具有实体Words,属性word,lengthlanguage。两者都被编入索引: Entity and attributes简单核心数据提取非常缓慢

我将cdatamodel和数据库复制到一个单独的导入器应用程序,在该应用程序中预填了大约400k字的不同语言。我通过查看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; 

是条目的数据库中的数核心数据的问题?


编辑: 作为gcbrueckmann和jrturton指出,这是一个好点的设置fetchBatchSize。但取时间仍然是不令人满意的:

  • 2秒谓词组:

    NSPredicate *谓词= [NSPredicate predicateWithFormat:@ “长度==%d与语言BEGINSWITH%@”,字长,LNG ]。 [fetchRequest setPredicate:predicate];

  • 7秒与批料尺寸集:

    [fetchRequest setFetchBatchSize:1];

  • 1与谓词和批量大小都第二套

是否还有另一个瓶颈?

+0

在你的谓词是语言可能比长度更严格,谓词检查有时为了能够加快速度为好。例如在这种情况下,如果有60%的单词符合您的长度标准,但只有40%符合语言标准,最好先进行语言检查。另一件事可能是,如果你需要更快的速度将是它预先加载,然后过滤内存中的数组不知道如果你的iPhone应用程序可以处理,但。 –

+0

在这种情况下,第一个查询是比较整数(索引将使这非常快),第二个是字符串比较(即使索引字符串不会很快) - 如果重新排序查询帮助,我会感到惊讶。但是,请尝试一下 - 我有兴趣看看它是否有帮助! – deanWombourne

+0

哦,我忘了提及它:我已经试图交换谓词的顺序,它不会加快取回。 – Norbert

回答

11

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

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

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

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

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

+0

'fetchBatchSize'绝对是一个好点。但不幸的是,它仍然需要2秒来抓住一个字。 – Norbert

+0

在你的情况下使用的是一个裸骨骼Sqlite数据库的选项吗?它看起来像现有的对象没有修改,所以核心数据可能不会有任何优于普通Sqlite的优势。 400,000真的是iPhone上的一个大型数据集。每种语言都有一个表是否可以选择? – gcbrueckmann

+0

是的,我已经想过切换回普通的SQLite,但我认为仍然可能存在一个我看不到的瓶颈。 – Norbert

1

这会将您的完整400k数据库存入内存,看起来好像很多。你可以调查其停止框架返回完整对象的一切在你的读取请求时,在您不需要每次返回的对象从店在第一时间获取的假设NSFetchRequest的

setFetchBatchSize 

方法。

2

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

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


PS您可以通过添加“-com.apple打开SQL调试。 CoreData.SQLDebug 1'作为启动时传递的参数(在您的Scheme中配置此参数) - 这可能有助于您了解SQL在幕后做了些什么。

(见this question了解详细信息)

+0

'语言BEGINSWITH%@'耗时600毫秒(平均); 'language ==%@'花了350ms(平均)! – Norbert

+1

我相信在这些方面我也看到它说要像比较语言> =%@那样做比使用BEGINSWITH更快。我想说这是在2010年WWDC核心数据视频中。 –

+0

如果这仍然是字符串相等,那么如果转换为比较整数,则会得到更多的加速;)SQL中的字符串索引只考虑字符串中的一定数量的字符,而索引整数是理想的! - http://dev.mysql.com/doc/refman/5.0/en/create-index.html – deanWombourne