具有BOOL检查的NSFetchRequest谓词是SLOW

sam*_*tte 6 iphone core-data

考虑通过5k +条目存储过滤以下2个谓词:

predicate1 = [NSPredicate predicateWithFormat:@"hidden == NO AND name BEGINSWITH[cd] %@", searchString];
predicate2 = [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", searchString];
Run Code Online (Sandbox Code Playgroud)

我打开-com.apple.CoreData.SQLDebug后看到了获取请求的次数:

谓词1:0.4728s
谓词2:0.0867s

我错过了什么吗?两列都已编入索引.为什么添加一个简单的布尔检查会减慢获取请求的速度呢?

编辑:根据要求,输出:

CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZHIDDEN, t0.ZID, t0.ZNAME, t0.ZRANK FROM ZARTISTINDEX t0 WHERE ( t0.ZHIDDEN = ? AND ( NSCoreDataStringSearch( t0.ZNAME, ?, 393, 0) OR  NSCoreDataStringSearch( t0.ZNAME, ?, 393, 0))) ORDER BY t0.ZRANK DESC LIMIT 14
Run Code Online (Sandbox Code Playgroud)

rank列也被编入索引.我需要此请求超过0.5秒的原因是它用于自动完成功能.每次用户更改某个文本字段的值时,都会发出该请求.

编辑2:添加更多上下文信息:

- (NSArray*)autocompleteSuggestions:(NSString*)searchString {

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"ArtistIndex" inManagedObjectContext:self.indexObjectContext];
    [request setEntity:entity];
    [request setFetchLimit:10];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"hidden == NO AND (name BEGINSWITH[cd] %@ OR name BEGINSWITH[cd] %@)", searchString, [NSString stringWithFormat:@"the %@", searchString]];
    [request setPredicate:predicate];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"rank" ascending:NO];
    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    [sortDescriptor release];

    NSArray *resultsArray = [self.indexObjectContext executeFetchRequest:request error:nil];
    [request release];

    return resultsArray;
}
Run Code Online (Sandbox Code Playgroud)

ArtistIndex实体具有以下属性:

  • id(int32)
  • name(字符串,索引)
  • rank(int32,indexed)
  • 隐藏(BOOL,索引)

编辑3:这里是慢查询(predicate1)的完整SQL输出和设置为3 的快速查询(predicate2)com.apple.CoreData.SQLDebug.更严格的测试为我带来了以下测试时间,这些测试时间更好,但仍然有+ 2x的差异,真正在自动填充建议上下文中有所作为.或者现在这是一个合理的获取时间差?

谓词1:0.3772s
谓词2:0.1633s

sam*_*tte 2

我最终接受了@pothibo和 Ivo Jansch 的回答第二种方法的建议,并执行以下操作:

  1. 当用户在字段中输入第一个字母时,我会获取以该字母开头的所有条目(因此基本上调用该autocompleteSuggestions:方法,但不设置获取请求的 fetchLimit属性)
  2. 每次用户添加或删除字母时,请 NSPredicate使用 向最初获取的数组应用适当的值filteredArrayUsingPredicate:

这会导致初始请求稍微慢一些(尽管仍然< 1 秒),但后续的提取速度快如闪电。

这是执行自动完成建议的一种非常聪明的方法,因为新的自动完成建议集始终是前一个自动完成建议的子集。谢谢@pothibo!