【问题标题】:Core Data: fetching items is slow with predicate核心数据:使用谓词获取项目很慢
【发布时间】:2011-10-16 10:09:27
【问题描述】:

对于我的 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]];

【问题讨论】:

    标签: sqlite core-data nsfetchrequest


    【解决方案1】:

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

    改为使用 Xcode 中的模型编辑器,然后简单地勾选您想要索引的实体属性的“索引”选项。

    不确定,但也许这个谓词更容易优化:

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

    【讨论】:

    • 看来BETWEEN 是不可能的。另请参阅this post
    【解决方案2】:

    您在这里有效地运行了两次获取,一次获取获取计数,然后一次获取实际对象。这会减慢速度。

    您的谓词是“向后”。复合谓词评估第一个表达式,例如length &gt;= %d 然后评估第二个,例如length &lt;= %d 只针对第一个结果。因此,您应该将消除最多对象的测试放在首位。在这种情况下,length &lt;= %d 可能会消除更多对象,因此它应该位于谓词的首位。

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

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

    【讨论】:

    • 谢谢,现在我只获取一个具有预先确定的固定长度的属性(最小/最大显着降低了它的速度)。
    猜你喜欢
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 1970-01-01
    相关资源
    最近更新 更多