使用Core Data时是否可以使用复杂索引?

时间:2011-11-19 22:06:34

标签: objective-c ios database core-data indexing

我正在开发一款iOS闪存卡式学习应用程序,在加载时,需要从Core Data中获取大量数据。但是我需要的数据是实体的一个相当特定的子集,基于用户设置,所以有多个谓词涉及测试等价。我发现这些提取速度非常慢,根据对SQLite的研究,我认为索引在这里是个不错的选择。

现在,我理解(主要是通过阅读其他stackoverflow问题)SQLite和Core Data是两个不同的,基本上是正交的东西,不应该混淆。但是我的理解是你应该通过Core Data来完成任何类型的数据库工作和调整;在优化或设计应用程序中的对象持久性时,不应试图绕过并直接使用SQLite。

但我唯一可以在Core Data中找到索引的是模型中每个属性的一个“索引”复选框。而这只是没有做我正在寻找的那种优化。

这是获取请求,目前:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"SKUserItem" inManagedObjectContext:context];
fetchRequest.entity = entity;

NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"next" ascending:YES] autorelease];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

NSMutableArray *predicates = [NSMutableArray arrayWithCapacity:6];
[predicates addObject:[NSPredicate predicateWithFormat:@"next < %f", now() + (60.0*60.0*24.0)]];
[predicates addObject:[NSPredicate predicateWithFormat:@"next > %f", nextOffset]];
[predicates addObject:[NSPredicate predicateWithFormat:@"user == %@", user]];
[predicates addObject:[NSPredicate predicateWithFormat:@"langRaw == %d", lang]];

NSArray *stylePredicates = [NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"styleRaw == %d", SK_SIMP_AND_TRAD], [NSPredicate predicateWithFormat:@"styleRaw == %d", self.style], nil];
[predicates addObject:[NSCompoundPredicate orPredicateWithSubpredicates:stylePredicates]];

if([self.parts count] == 4 || (self.lang == SK_JA && [self.parts count] == 3))
    ;  // don't have to filter by parts; they're studying all of them
else {
    NSMutableArray *partPredicates = [NSMutableArray arrayWithCapacity:[self.parts count]];
    for(NSString *part in self.parts)
        [partPredicates addObject:[NSPredicate predicateWithFormat:@"partRaw == %d", partCode(part)]];
    [predicates addObject:[NSCompoundPredicate orPredicateWithSubpredicates:partPredicates]];
}

NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
fetchRequest.predicate = compoundPredicate;

所以这个fetch所做的基本上是接下来的排序(给定项目到期的时间)和过滤用户名,正在研究的语言,正在研究的样式(中文有简化和传统)和正在研究的部分(写作,音调,阅读或定义),只在“下一个”范围内提取。以下是我从调整和摆弄这些事情中学到的一些简短列表:

  1. 它总是扫描整个表格,或者似乎。虽然next是索引的,但即使我强制它搜索我知道也不会返回任何内容的范围,仍然需要几秒钟才能完成提取。
  2. 谓词,任意数量的谓词,都会让这个变慢。如果我删除一些但不是全部,那就慢了。如果我删除所有谓词(从而打破了应用程序),那么它会快得多。
  3. 速度在很大程度上取决于表中总共有多少UserItem。物品越多,越慢。有些人可以拥有成千上万的物品,而且这个物品的获取时间可能需要10秒才能完成。这导致我的应用程序出现尴尬停顿。
  4. 添加下一个值的上限并不是因为我们需要它,而是因为它加快了获取速度。
  5. 让查询返回字典中的属性子集(而不是整个托管对象)并且懒惰地获取其余属性更快,但仍然不够快。
  6. 我来自Google App Engine,所以我习惯了他们在那里提供的索引。基本上我想要那种索引,但是通过Core Data应用于SQLite。我找到了有关在SQLite中添加索引的信息,我想要的那种,但是通过Core Data进行这种索引,我找不到任何关于它的信息。

2 个答案:

答案 0 :(得分:18)

你想要的是一个复合索引,这是Core Data在iOS 5.0及更高版本中支持的。

您可以在Xcode中进行设置:实体检查器有索引部分,或者如果您在代码中创建NSEntityDescription,请使用{ {1}}。

如果您使用Xcode,则需要在索引部分添加一行

-setCompoundIndexes:

这样SQL就可以为您的查询使用索引。

答案 1 :(得分:2)

Core Data有一个SQL后端。你完成这项工作的方式是将所有数据放在一个表中(一个实体的一部分),并找到你要查找的对象需要搜索所有行,正如你所说的那样。

在您的数据模型中,您需要将要搜索的某些属性分解为其他实体。尝试使其更加基于对象并考虑您将要搜索的内容。

E.g。 有一个用户,语言的实体,也许还有一个用于课程的实体或者你正在搜索的任何基于时间的东西。

Lesson实体与Language有很多关系,与用户有一个关系。 (如果不止一个用户参加课程,则为很多人)

然后,要查找用户的数据,您需要获取该用户并调查她的语言或课程属性以了解更多信息。

要查找学习语言的用户列表,请获取您要查找的语言实体并调查用户属性。