【问题标题】:How do I set up relationship for large core data sets efficiently?如何有效地为大型核心数据集建立关系?
【发布时间】:2014-05-31 23:51:42
【问题描述】:

我有两个实体 Drink 和 Breweries。我有 Json 中的数据,我正在为每个数据构建核心数据表并建立关系(饮料与啤酒厂一对一)。但是,在构建 Drink 对象时尝试设置它显然会大大减慢该过程,因为我每次创建新饮料时都必须查询核心数据(有几千个饮料和大约 1000 家啤酒厂)。目前,啤酒厂有一个与饮料属性相匹配的唯一 ID。在不大大减慢加载时间的情况下,最好的方法是什么?我正在考虑只使用一个实体并将啤酒厂放在同一张表中,即使这是不好的数据库做法。

这是从 json 中构建饮料表的代码,其中添加啤酒厂的代码已注释掉。

[jsonCategories enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
    Drink *drink = [NSEntityDescription insertNewObjectForEntityForName:@"Drink" inManagedObjectContext:importContext];
    //drinkType.id = [obj objectForKey:@"id"];
    drink.name = [obj objectForKey:@"name"];
    drink.alcoholByVolume = [obj objectForKey:@"abv"];
    drink.drinkType = beerDrinkType;
    drink.breweryId = [obj objectForKey:@"brewery_id"];


//        NSArray *fetchedObjects;
//        NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
//        NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Breweries" inManagedObjectContext:importContext];
//        [fetch setEntity:entityDescription];
//        [fetch setPredicate:[NSPredicate predicateWithFormat:@"id =%@", drink.breweryId]];
//        NSError *errorBrewery;
//        [fetch setFetchLimit:1];
//        fetchedObjects = [importContext executeFetchRequest:fetch error:&errorBrewery];
//        if (fetchedObjects && [fetchedObjects count] > 0){
//        Breweries *fetchedBrewery = [fetchedObjects objectAtIndex:0];
//        drink.breweries = fetchedBrewery;
//        }

}];

【问题讨论】:

    标签: ios json core-data


    【解决方案1】:

    您正在使用 jsonCategories 元素的每次迭代重新获取啤酒厂列表。这会增加巨大的开销并导致速度变慢,并且是不必要的,因为我假设列表不会改变。

    更好的设计是获取一次,然后根据需要对其进行过滤。下面我省略了一些代码,只写了重要的部分,你应该可以自己填写。

    NSFetchRequest *fetch = …;
    // Note that predicate is not set here
    fetchedBreweries = [importContext executeFetchRequest…];
    [jsonCategories enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
        …
        NSArray *matchingBreweries = [fetchedBreweries filteredArrayUsingPredicate:…predicate];
        drink.breweries = matchingBreweries.firstObject;
    }];
    

    也许这也会很慢,因为如果您获取所有啤酒厂,它可能会消耗过多的 CPU 和内存(尽管我会先尝试一下,看看这是否真的有问题)。

    进一步的优化可能是您首先遍历 jsonCategories 并创建一组可在结果中找到的啤酒厂 ID。然后,您只获取这些啤酒厂,然后再次迭代饮料结果以将啤酒厂添加到饮料中。这就像

    NSMutableSet *breweryIds = [NSMutableSet set];
    [jsonCategories enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
        …
        [breweryIds addObject:[obj objectForKey:@"brewery_id"]];
    }];
    NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
    [fetch setPredicate:[NSPredicate predicateWithFormat:@"id in %@", breweryIds]];
    NSArray *breweries = [importContext executeFetchRequest…]
    for (Drink *drink in drinks) {
        NSArray *matchingBreweries = [fetchedBreweries filteredArrayUsingPredicate:…predicate];
        drink.breweries = matchingBreweries.firstObject;
    }
    

    嗯。我现在需要一杯啤酒。

    【讨论】:

    • 实际上在我的手机上测试它 (5),构建饮料数据库和啤酒厂数据库需要整整 40 秒,然后使用谓词过滤获取的啤酒厂数组。我真的想不出办法让这更快,所以我可能只需要用实际的啤酒厂名称替换 id。
    猜你喜欢
    • 2016-12-17
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多