1

我正在后台队列中的子 moc 中进行数据处理。我需要按 ID 查询数据库,以便区分更新现有对象和创建新对象。我发现大部分时间(50 个项目的总处理时间约为 2 秒)被executeFetchRequest:error:. is 是最NSPredicate简单的形式——只匹配单个 ID 属性(ID 属性已被索引),并且NSFetchRequest应该返回一个或无(ID 是唯一的)。有没有办法优化这种NSFetchRequest

这是我当前的代码:

+ (User *)userWithID:(NSNumber *)ID inManagedObjectContext:(NSManagedObjectContext *)context {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"User"];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ID == %@", ID];
    [fetchRequest setPredicate:predicate];
    [fetchRequest setFetchBatchSize:1];

    NSError *error = nil;
    NSArray *users = [context executeFetchRequest:fetchRequest error:&error];
    if (error) {
        abort();
    }

    if ([users count] == 1) {
        return [users objectAtIndex:0];
    } else if ([users count] > 1) {
        // Sanity check.
        …
    } else {
        return nil;
    }
}
4

2 回答 2

1

正如@ChrisH 在问题下的评论中指出的那样,为每个 ID 进行提取是不好的。因此,我将处理流程更改为:

  1. 第一次枚举数据以提取 ID。
  2. 执行一次 fetch 以获取所有与 ID 匹配的现有用户,并将它们放入以 ID 为键的字典中(命名为existingUsers)。
  3. 第二次枚举数据进行真正的处理:在每次迭代中,要么更新在其中找到的一个现有用户,existingUsers要么创建一个新用户,existingUsers如果是新用户,则将其添加。

代码几乎翻了一番,但性能也是如此。真的很好的权衡!

于 2012-10-03T02:17:30.787 回答
1

为了扩展我对原始问题的评论,在导入数据时重复使用 Core Data 执行获取请求效率不高。

正如@an0 所指出的,最简单的方法是对您将要检查的所有现有对象执行一次提取,然后构造一个 NSDictionary,其中包含您将要检查的属性作为键的对象。所以坚持原来的 User 和 userID 例子:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"User"];

NSError *error = nil;

NSArray *users = [context executeFetchRequest:fetchRequest error:&error];

if (error) {
  //handle appropriately
}

NSMutableDictionary *userToIdMap = [NSMutableDictionary dictionary];

for (User *user in users){

  [userToIdMap setObject:user forKey:user.ID];

}

现在在处理新数据的方法中,您可以检查userToIdMap字典而不是发出获取请求。

Core Data Programming Guide 的Efficently Importing Data中概述了一种更复杂的方法,适用于更大的数据集。查看名为“高效实施查找或创建”的部分。Apple 在此处建议的方法遗漏了一些有关如何遍历您创建的数组的代码,我对该问题的解决方案是在这个 SO 问题中:Basic array comparison algorithm

于 2012-10-03T16:53:07.203 回答