- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
使用 CoreData 时,以下多列索引谓词非常慢 - 26,000 条记录需要将近 2 秒。
请注意,两列都已编入索引,我特意使用 > 和 <= 而非开头来进行查询,以加快查询速度:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"airportNameUppercase >= %@ AND airportNameUppercase < %@ \
OR cityUppercase >= %@ AND cityUppercase < %@ \
upperText, upperTextIncremented,
upperText, upperTextIncremented];
但是,如果我运行两个单独的 fetchRequests,每个列一个,然后我合并结果,那么每个 fetchRequest 只需要 1-2 百分之一秒,而合并列表(已排序)大约需要 1/十分之一秒。
这是 CoreData 处理多个索引的错误,还是这是预期的行为?以下是我的完整优化代码,运行速度非常快:
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init]autorelease];
[fetchRequest setFetchBatchSize:15];
// looking up a list of Airports
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Airport"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// sort by uppercase name
NSSortDescriptor *nameSortDescriptor = [[[NSSortDescriptor alloc]
initWithKey:@"airportNameUppercase"
ascending:YES
selector:@selector(compare:)] autorelease];
NSArray *sortDescriptors = [[[NSArray alloc] initWithObjects:nameSortDescriptor, nil]autorelease];
[fetchRequest setSortDescriptors:sortDescriptors];
// use > and <= to do a prefix search that ignores locale and unicode,
// because it's very fast
NSString *upperText = [text uppercaseString];
unichar c = [upperText characterAtIndex:[text length]-1];
c++;
NSString *modName = [[upperText substringToIndex:[text length]-1]
stringByAppendingString:[NSString stringWithCharacters:&c length:1]];
// for the first fetch, we look up names and codes
// we'll merge these results with the next fetch for city name
// because looking up by name and city at the same time is slow
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"airportNameUppercase >= %@ AND airportNameUppercase < %@ \
OR iata == %@ \
OR icao == %@",
upperText, modName,
upperText,
upperText,
upperText];
[fetchRequest setPredicate:predicate];
NSArray *nameArray = [context executeFetchRequest:fetchRequest error:nil];
// now that we looked up all airports with names beginning with the prefix
// look up airports with cities beginning with the prefix, so we can merge the lists
predicate = [NSPredicate predicateWithFormat:
@"cityUppercase >= %@ AND cityUppercase < %@",
upperText, modName];
[fetchRequest setPredicate:predicate];
NSArray *cityArray = [context executeFetchRequest:fetchRequest error:nil];
// now we merge the arrays
NSMutableArray *combinedArray = [NSMutableArray arrayWithCapacity:[cityArray count]+[nameArray count]];
int cityIndex = 0;
int nameIndex = 0;
while( cityIndex < [cityArray count]
|| nameIndex < [nameArray count]) {
if (cityIndex >= [cityArray count]) {
[combinedArray addObject:[nameArray objectAtIndex:nameIndex]];
nameIndex++;
} else if (nameIndex >= [nameArray count]) {
[combinedArray addObject:[cityArray objectAtIndex:cityIndex]];
cityIndex++;
} else if ([[[cityArray objectAtIndex:cityIndex]airportNameUppercase] isEqualToString:
[[nameArray objectAtIndex:nameIndex]airportNameUppercase]]) {
[combinedArray addObject:[cityArray objectAtIndex:cityIndex]];
cityIndex++;
nameIndex++;
} else if ([[cityArray objectAtIndex:cityIndex]airportNameUppercase] <
[[nameArray objectAtIndex:nameIndex]airportNameUppercase]) {
[combinedArray addObject:[cityArray objectAtIndex:cityIndex]];
cityIndex++;
} else if ([[cityArray objectAtIndex:cityIndex]airportNameUppercase] >
[[nameArray objectAtIndex:nameIndex]airportNameUppercase]) {
[combinedArray addObject:[nameArray objectAtIndex:nameIndex]];
nameIndex++;
}
}
self.airportList = combinedArray;
最佳答案
CoreData 无法创建或使用多列索引。这意味着当你执行你的多属性谓词对应的查询时,CoreData 只能使用一个索引来进行选择。随后它使用索引进行其中一个属性测试,但是 SQLite 无法使用索引来收集第二个属性的匹配项,因此必须在内存中完成所有操作,而不是使用其磁盘索引结构。
选择的第二阶段最终变得很慢,因为它必须将所有结果从磁盘收集到内存中,然后进行比较并将结果放入内存中。因此,与使用多列索引相比,您最终可能会执行更多的 I/O。
这就是为什么,如果您要取消谓词每一列中的许多潜在结果,那么通过执行您正在做的事情并进行两次单独的提取并在内存中合并,您将比您更快地看到结果如果你做了一次取回,会怎样。
为了回答您的问题,Apple 并不意外这种行为;这只是不支持 CoreData 中的多列索引的设计决策的结果。但是你应该在 https://feedbackassistant.apple.com/ 提交错误如果您希望在未来看到该功能,请请求支持多列索引。
与此同时,如果你真的想在 iOS 上获得最大的数据库性能,你可以考虑直接使用 SQLite 而不是 CoreData。
关于objective-c - 这是我应该提交给 Apple 的错误,还是这是预期的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5111865/
因为我需要一个指向不同类中的 SDL_Window 的指针,所以我认为使用 shared_ptr 是个好主意。 //happens in class A::foo() //shared_Window_
我有一些通过 cron 定期运行的长期运行的 CLI PHP 脚本。我希望它们尽快完成,但又不会严重影响其他进程(例如 Web 服务器响应能力)。 目前我正在运行脚本 nice -n 19 并且还尝试
我想将 view.py 中的字符串数组移交给模板,并将该字符串用于 D3。 views.py: def index(request): template = loader.get_templa
我必须使用一个库函数,它为生成的字符串分配一点内存并返回一个 char*,期望调用者最终使用 free() 释放内存。 // Example declaration of the library fu
我想使用接受 UTF16-LE 字符串作为 (const char16_t* str, size_t length) 参数的库函数。 length 参数只需要为非空终止的字符串提供。该函数将复制字符串
我是一名优秀的程序员,十分优秀!