核心数据:使用谓词获取项目很慢

时间:2011-07-30 06:05:22

标签: sqlite core-data nsfetchrequest

对于我的iPhone应用程序,我为Core Data设置了一个数据模型。它包含一个实体Words,其属性为language : Stringlength : Integer16word : String

我用一个单词列表(200k项目)预填充模型的SQLite数据库,使用相同的数据模型编写单独的iPhone应用程序,并将填充的数据库复制到主应用程序。

现在使用NSFetchedRequest我可以随意查询托管对象,但结果很慢。我使用以下方法:

- (NSString *)getRandomWordLengthMin:(int)minLength max:(int)maxLength
{
    NSString *word = @"";

    MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Words"
                                              inManagedObjectContext:context];
    [fetchRequest setEntity:entity];

    NSString *predicateString = @"length >= %d AND length <= %d";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString,
                              minLength, maxLength];
    [fetchRequest setPredicate:predicate];

    NSError *error = nil;
    int entityCount = [context countForFetchRequest:fetchRequest error:&error];
    [fetchRequest setFetchLimit:1];
    if(entityCount != 0)
    {
        [fetchRequest setFetchOffset:arc4random()%entityCount];
    }

    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
    if([fetchedObjects count] != 0)
    {
        Words * test = [fetchedObjects objectAtIndex:0];
        word = [NSString stringWithFormat:@"%@", [test word]];
    }

    return word;
}

使用SQLite编辑器我已经在zLength列上手动设置了索引,但这并没有带来任何加速。瓶颈在哪里?

修改

我发现获得int entityCount = ...的速度很慢。但即使获取所有对象然后选择一个随机单词也很慢:

Words * test = [fetchedObjects objectAtIndex:arc4random()%[fetchedObjects count]];

2 个答案:

答案 0 :(得分:3)

你实际上在这里运行两次提取,一次获取获取计数,然后一次获取实际对象。这会减慢速度。

你的谓词是“倒退”。复合谓词评估第一个表达式,例如length >= %d,然后评估第二个,例如length <= %d仅针对第一个结果。因此,您应该首先进行消除大多数对象的测试。在这种情况下,length <= %d可能会消除更多对象,因此它应该首先出现在谓词中。

由于您实际上不需要整个Words托管对象而只需要word字符串,因此可以将获取返回类型设置为NSDictionaryResultType,然后将属性设置为fetch to只是word属性。这将大大加快速度。

这里的部分问题是Core Data旨在管理结构化对象图,并且您正在使用随机/非结构化图形,因此您正在削减Core Data的优化。

答案 1 :(得分:1)

不要使用SQLite编辑器编辑Core Data存储的SQLite后备存储。数据库的内部是私有的,可能会发生变化。

而是转到Xcode中的模型编辑器,只需勾选要索引的实体属性的“索引”选项。

不确定但是这个谓词可能更容易优化:

NSString *predicateString = @"length BETWEEN (%d, %d)";