Производительность: отношения основных данных нарушаются после назначения - PullRequest
6 голосов
/ 12 августа 2011

У меня есть модель Core Data, представляющая телегида на iOS 4+, с 3 классами:

  • Channel (BBC 1)
  • Program (Top Gear)
  • Broadcast (Top Gear на BBC 1 в понедельник в 8 вечера)

У меня около 40 каналов, 8000 программ и 6000 трансляций, и я хотел бы настроитьпроцесс импорта, чтобы его выполнение не занимало минуты.

Импортировать каналы и программы легко, поскольку они являются независимыми объектами.Однако трансляция имеет отношение к каналу и программе (1-ко-многим), а каналы и программы имеют обратную связь с трансляциями (многие-к-1).Чтобы ускорить процесс, у меня есть словарь в памяти каналов ошибок и программ, для которых предварительно выбран только их идентификатор веб-службы: я создаю трансляцию и просматриваю оба словаря, чтобы получить соответствующий канал и программу без обращения к базе данных.

Но когда я назначаю программу или канал для трансляции, доступ к обратным отношениям канала и программы сразу же вызывает ошибку обоих объектов, вызывая значительное замедление (6000 * 2 запросов) и последующее давление памятипоказано в отчете о неисправностях основных данных.Я пытался предварительно извлечь отношения broadcasts на обоих каналах и в программах, но отношения все равно становятся ошибочными.

Есть ли у вас какие-либо идеи, почему обратные отношения получают доступ к своим родителям?Как избежать чтения из базы данных при сохранении отношений?

ОБНОВЛЕНИЕ: Пример кода, мой метод назначения / обновления для экземпляра Broadcast.Переменная dictionary поступает из веб-службы, а channels и programs содержат каналы ошибок и объекты программ, проиндексированные по идентификатору веб-службы.Ошибка происходит в строках self.program = program и self.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 Ответ

1 голос
/ 13 августа 2011

Не совсем уверен, что вы пытаетесь сделать здесь, но ...

Первое, что вы не можете изменять свойства, используя только ошибки. Неисправности - это просто заполнители, которые позволяют вам измерять / подсчитывать граф объектов и обходить отношения. Если вы на самом деле измените отношение, оно вызовет ошибку, вызвав загрузку связанных объектов.

Если вы пытаетесь установить отношения между конкретными объектами Channel, Program и Broadcast, используя только ошибки, это не сработает.

Ваш itemsForEntity: метод, который я не понимаю. Он извлечет каждый существующий управляемый объект переданного объекта, а затем вернет эти объекты в словарь. Это приведет к огромным накладным расходам памяти, особенно в случае Program объектов, которых насчитывается 8000.

Вы не можете использовать propertiesToFetch, если не установите выборку возврата в словарь, чего вы не делаете. Вы не можете использовать тип возвращаемого словаря в любом случае, если вам нужно установить отношения. Вы используете оба этих параметра, когда вам нужны только данные, хранящиеся в определенных атрибутах. Это не инструмент для манипулирования отношениями графа объекта.

Установка relationshipKeyPathsForPrefetching только ускоряет процесс, если вы знаете, что будете иметь доступ к существующим отношениям. Это не помогает, когда вы устанавливаете отношения в первую очередь, например, если в отношениях broadcasts нет существующих объектов или вы добавляете или удаляете объекты Broadcast, предварительная выборка ключа broadcasts ничего не изменит для вас.

Я не уверен, что понимаю вашу модель данных достаточно хорошо, но я думаю, что вы делаете это неправильно. Мне кажется, что вы пытаетесь использовать identifier как первичный ключ в базе данных SQL, и это контрпродуктивно. В Базовых данных отношение связывается с объектами вместе, а не с общим атрибутом и значением.

Как правило, если у вас есть два или более объектов с одинаковым именем атрибута с одинаковым значением, то в большинстве случаев у вас получается плохо спроектированная модель данных.

...