考虑通过5k +条目商店过滤以下2个谓词:
predicate1 = [NSPredicate predicateWithFormat:@"hidden == NO AND name BEGINSWITH[cd] %@", searchString];
predicate2 = [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", searchString];
我打开-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
该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;
}
ArtistIndex
实体具有以下属性:
编辑3 :以下是slow query (predicate1)和fast query (predicate2) com.apple.CoreData.SQLDebug
设置为3的完整SQL输出。更严格的测试为我带来了以下内容测试时间,这是更好的,但仍然有+ 2倍的差异,并真正在自动完成建议上下文中有所作为。或者现在这是一个合理的获取时间差异?
谓词1:0.3772s
谓词2: 0.1633s
答案 0 :(得分:2)
对于2列的where子句和仅1的索引,sqlite可能决定在布尔字段上使用索引。这导致快速选择,但它会在内部产生一半的数据集加载;然后它开始做另一个子句,但它需要通过查看每个记录来做到这一点。这就是布尔搜索引起减速的原因。
我认为你应该尝试3种方法。
除非两列都有一个索引,否则2列上的查询将表现不佳。我不相信Core Data允许您在单个索引中索引多个列,但底层的SQLite数据库可以。因此,只要看看这是否是导致问题的原因,请尝试在两列上的sqlite数据库上手动创建索引。重要的是你的布尔值是索引中的第二列,因为它没有足够的区别(它只有2个值所以它需要过滤的数据集是数据库的一半;这使得索引效率略低)。
添加一个实用程序列,其中包含名称和隐藏字段的串联,并对其进行索引和搜索。这可能不太有效,因为您匹配子字符串。
如果hidden = YES的记录数量很小,只需将其从谓词中删除并在之后过滤它们。
答案 1 :(得分:2)
我最终在@pothibo和Ivo Jansch的回答第二种方法上采取了建议并做了以下事情:
autocompleteSuggestions:
方法,但不设置获取请求
fetchLimit
财产)NSPredicate
使用filteredArrayUsingPredicate:
初始获取的数组。这会导致初始请求速度稍慢(尽管仍然<1s),但后续提取闪电般快速。
这是一种非常聪明的方法来执行自动填充建议,因为新的自动填充建议集始终将成为前一个的子集。谢谢@pothibo!
答案 2 :(得分:1)
CoreData并不是真的在这两个查询之间做了很多。这种减速有两种可能的原因,两者都可以通过在Xcode中的应用程序启动参数上设置-com.apple.CoreData.SQLDebug 3来诊断。
解决方案: