При использовании CoreData следующий предикат индекса нескольких столбцов выполняется очень медленно - для 26 000 записей требуется почти 2 секунды.Является ли это ошибкой, которую я должен представить Apple, или это ожидаемое поведение?
Пожалуйста, обратите внимание, обе колонки индексируются, и я намеренно делаю запрос с> и < = вместо beginswith, чтобы сделать это быстро:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"airportNameUppercase >= %@ AND airportNameUppercase < %@ \
OR cityUppercase >= %@ AND cityUppercase < %@ \
upperText, upperTextIncremented,
upperText, upperTextIncremented];
Однако, если я запускаю два отдельных fetchRequests, один для каждого столбца, а затем я объединяю результаты, тогда каждый fetchRequest занимает всего 1-2 сотки секунды, а слияние списков (которые сортируются) занимает около 1/10 секунды.
Является ли это ошибкой в том, как 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;
Похоже, вы пытаетесь преждевременному оптимизируют ваш запрос предикатами. Вы пробовали более простые предикаты и обнаружили, что они еще медленнее? –
В стороне, вы явно думаете об этом в терминах SQL, что приведет к горя в Core Data. Хотя Core Data часто использует хранилище SQLite, это последнее дополнение и фактически не имеет ничего общего с основной функцией Core Data, которая управляет графами объектов в памяти. – TechZen