性能:核心数据关系在分配后出现故障

时间:2011-08-12 14:04:14

标签: iphone ios core-data entity-relationship

我有一个Core Data模型代表iOS 4+上的电视指南,有3个类:

  • Channel(BBC 1)
  • Program(Top Gear)
  • Broadcast(周一晚上8点BBC 1的Top Gear)

我有大约40个频道,8000个节目和6000个广播,我想微调导入过程,这样就不需要花一分钟的时间来运行。

导入频道和节目非常简单,因为它们是独立的对象。然而,广播与频道和节目(1对多)有关系,并且频道和节目都与广播(多对1)具有反向关系。为了加快速度,我有一个故障通道的内存字典和只预取了Web服务标识符的程序:我创建一个广播并查看两个字典,以获得相应的通道和程序,而无需往返数据库。

但是当我将节目或频道分配给广播时,频道和节目的反向关系访问会立即触发两个对象的故障,导致大幅减速(6000 * 2请求)和随之而来的内存压力,如核心数据故障仪器报告。我尝试在两个频道和节目上预先获取broadcasts关系,但这种关系仍然存在问题。

你知道为什么反向关系被访问并且他们的父母有错吗?保存关系时如何避免从数据库中读取?

更新:示例代码,Broadcast实例的分配/更新方法。 dictionary变量来自Web服务,channelsprograms包含由Web服务标识符索引的故障通道和程序对象。错误发生在self.program = programself.channel = channel行。

- (BOOL)assignWithDictionary:(NSDictionary *)dictionary channels:(NSDictionary *)channels programs:(NSDictionary *)programs {
    // Add channel relationship
    NSNumber *channelIdentifier = [dictionary objectForKey:@"channel_id"];

    if (self.channel == nil || ![self.channel.identifier isEqualToNumber:channelIdentifier]) {
        Channel *channel = [channels objectForKey:channelIdentifier];

        if (channel == nil) {
            NSLog(@"Broadcast %@ has invalid channel: %@", identifier, channelIdentifier);

            return NO;
        }

        self.channel = channel;
    }

    // Same to add a program relationship
    // ...
}

我获取频道或节目列表的获取请求:

- (NSDictionary *)itemsForEntity:(NSEntityDescription *)entity {
    NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
    NSError *error = nil;
    NSArray *itemsArray = nil;

    request.entity = entity;

    request.relationshipKeyPathsForPrefetching = [NSArray arrayWithObject:@"broadcasts", nil];
    request.propertiesToFetch = [NSArray arrayWithObjects:@"identifier", @"version", nil];

    itemsArray = [self.context executeFetchRequest:request error:&error];
    NSAssert1(error == nil, @"Could not fetch the items from the database: %@", error);

    {
        NSMutableDictionary *items = [NSMutableDictionary dictionaryWithCapacity:itemsArray.count];

        for (NSManagedObject *item in itemsArray) {
            [items setObject:item forKey:[item valueForKey:@"identifier"]];
        }

        return [NSDictionary dictionaryWithDictionary:items];
    }
}

1 个答案:

答案 0 :(得分:1)

不完全确定你在这里要做什么,但......

首先,您不能仅使用故障来改变属性。错误只是占位符,允许您测量/计算对象图和步行关系。如果您实际改变了关系,它将触发故障导致相关对象加载。

如果您尝试仅使用故障在特定ChannelProgramBroadcast对象之间设置关系,那将无效。

我的itemsForEntity:方法我不明白。它将获取传递的实体的每个现有托管对象,然后它将在字典中返回这些对象。这将导致巨大的内存开销,特别是在Program对象的情况下,其中有8,000个。

除非您将fetch返回到字典,否则不能使用propertiesToFetch。如果需要设置关系,则无论如何都不能使用字典返回类型。当你想要的只是某些属性中保存的数据时,你可以同时使用它们。它不是用于操纵对象图的关系的工具。

如果您知道自己将访问现有关系,那么设置relationshipKeyPathsForPrefetching只会加快速度。当您首先设置关系时,它没有帮助,例如如果broadcasts关系中没有现有对象,或者您正在添加或删除Broadcast个对象,则预取broadcasts密钥路径对您无效。

我不确定我是否理解你的数据模型,但我认为你的方法是错误的。在我看来,您试图在SQL数据库中使用identifier像主键,这会适得其反。在Core Data中,关系链接到对象,而不是共享属性和值。

通常,如果您有两个或多个具有相同属性名称且具有相同值的对象,则在大多数情况下您的数据模型设计不佳。