Ios 尝试将服务器内容同步到核心数据时出现问题-神奇的记录插入过程极其缓慢

Ios 尝试将服务器内容同步到核心数据时出现问题-神奇的记录插入过程极其缓慢,ios,objective-c,cocoa-touch,core-data,magicalrecord,Ios,Objective C,Cocoa Touch,Core Data,Magicalrecord,我能够成功地将我的数据库同步到核心数据中。我使用它作为我的核心数据包装接口 我面临的问题是插入所有信息的过程非常缓慢。 我知道这个问题可能太具体了。但我真的相信Obj-C代码中有一些我遗漏的琐碎的东西 这是我尝试同步的部分DB的结构 首先是一些背景信息。 每个地方都有: 一(1)参考行到位\u联系人\u信息 一(1)参考行就地调整 七(7)参考行到位\u营业时间 零(0)个或多个引用的行位于适当的标记和类别中 数据库(服务器端)目前由约1000个位置组成 我在服务器端的PHP脚本以JSON

我能够成功地将我的数据库同步到核心数据中。我使用它作为我的核心数据包装接口

我面临的问题是插入所有信息的过程非常缓慢。 我知道这个问题可能太具体了。但我真的相信Obj-C代码中有一些我遗漏的琐碎的东西

这是我尝试同步的部分DB的结构

首先是一些背景信息。

每个地方都有:

  • 一(1)参考行到位\u联系人\u信息
  • 一(1)参考行就地调整
  • 七(7)参考行到位\u营业时间
  • 零(0)个或多个引用的行位于适当的标记和类别中
数据库(服务器端)目前由约1000个位置组成

我在服务器端的PHP脚本以JSON格式提供此数据的表示

它的交付方式如下所示:

这里是我对核心数据逻辑的插入

data
这是上面链接中描述的部分数据库的完整表示

+ (void)updateDatabaseWithPlaces:(NSDictionary *)data
{   
    [FFSynchronizationHandler synchronizePlaces:[data objectForKey:@"places"]];
    [FFSynchronizationHandler synchronizeContactInfo:[data objectForKey:@"place_contact_info"]];
    [FFSynchronizationHandler synchronizeOpeningHours:[data objectForKey:@"opening_hours"]];
    [FFSynchronizationHandler synchronizeAdjustments:[data objectForKey:@"place_adjustments"]];
    [FFSynchronizationHandler synchronizeCategories:[data objectForKey:@"place_category"]];
    [FFSynchronizationHandler synchronizeTags:[data objectForKey:@"place_tag"]];

    [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) {

        [[NSNotificationCenter defaultCenter]postNotificationName:SYNCHRONIZATION_COMPLETE object:nil];

    }];
}


+ (void)synchronizePlaces:(NSDictionary*)places
{
    for(id placeParams in places)
    {
        Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:@([[placeParams objectForKey:@"id"]integerValue])];

        // if the place is flagged as deleted, delete that entity
        if([[placeParams objectForKey:@"is_deleted"]integerValue] == 1){
            [place MR_deleteEntity];
            continue;
        } else if(!place){
            // if the place does not exists in the database already, create it.
            place = [Place MR_createEntity];
        }
        place.place_id = @([[placeParams objectForKey:@"id"]integerValue]);
        place.name = [placeParams objectForKey:@"name"];
        place.longitude = @([[placeParams objectForKey:@"longitude"]floatValue]);
        place.latitude = @([[placeParams objectForKey:@"latitude"]floatValue]);
        place.main_category = @([[placeParams objectForKey:@"main_category"]integerValue]);
        place.info_text = [placeParams objectForKey:@"info_text"] == [NSNull null] ? nil :[placeParams objectForKey:@"info_text"];
    }
    [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
}


+ (void)synchronizeContactInfo:(NSDictionary*)contactInfoParams
{
    for(id contactInfo in contactInfoParams)
    {
        Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:@([[contactInfo objectForKey:@"place_id"] integerValue])];

        // if the place that the contact info belongs to
        // is somehow not here, just continue the loop
        if(place == nil)
            continue;
        PlaceContactInfos *place_contact_info = [PlaceContactInfos MR_createEntity];
        place_contact_info.website = [contactInfo objectForKey:@"website"] == [NSNull null] ? nil :[contactInfo objectForKey:@"website"];
        place_contact_info.telephone = [contactInfo objectForKey:@"telephone"] == [NSNull null] ? nil : [contactInfo objectForKey:@"telephone"];
        place_contact_info.email = [contactInfo objectForKey:@"email"] == [NSNull null] ? nil : [contactInfo objectForKey:@"email"];
        place_contact_info.address = [contactInfo objectForKey:@"address"] == [NSNull null] ? nil : [contactInfo objectForKey:@"address"];
        place_contact_info.city = [contactInfo objectForKey:@"city"] == [NSNull null] ? nil : [contactInfo objectForKey:@"city"];
        place_contact_info.zip_code = [contactInfo objectForKey:@"zip_code"] == [NSNull null] ? nil : [contactInfo objectForKey:@"zip_code"];
        place_contact_info.country = [contactInfo objectForKey:@"country"] == [NSNull null] ? nil : [contactInfo objectForKey:@"country"];
        place.place_contact_info = place_contact_info;

    }
    [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
}

+ (void)synchronizeOpeningHours:(NSDictionary*)openingHoursParams
{
    for(id openingHours in openingHoursParams)
    {
        NSNumber* openingHoursId = @([[openingHours objectForKey:@"id"]integerValue]);
        NSNumber* placeId = @([[openingHours objectForKey:@"place_id"]integerValue]);
        NSNumber* isDeleted = @([[openingHours objectForKey:@"is_deleted"] integerValue]);
        Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:placeId];

        // if the place is flagged as deleted, delete that entity
        if(isDeleted.integerValue > 0){
            PlaceOpeningHours *oh = [PlaceOpeningHours MR_findFirstWithPredicate:[NSPredicate predicateWithFormat:@"place_id = %@ AND oh_id = %@",placeId, openingHoursId]];
            if(oh)
                [oh MR_deleteEntity];
        } else {
            PlaceOpeningHours *oh = [PlaceOpeningHours MR_createEntity];
            oh.day =  @([[openingHours objectForKey:@"day"]integerValue]);
            oh.open = [openingHours objectForKey:@"open"] == [NSNull null] ? nil : [openingHours objectForKey:@"open"];
            oh.close = [openingHours objectForKey:@"close"] == [NSNull null] ? nil : [openingHours objectForKey:@"close"];
            oh.always_open = @([[openingHours objectForKey:@"always_open"]integerValue]);
            oh.is_closed = @([[openingHours objectForKey:@"is_closed"]integerValue]);
            oh.place_id = placeId;
            oh.place = place;
        }

    }
     [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
}


+ (void)synchronizeAdjustments:(NSDictionary*)adjustmentsParams
{
    for(id adjustmentParams in adjustmentsParams)
    {
        Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:@([[adjustmentParams objectForKey:@"place_id"] integerValue])];
        // if the place that the adjustments belongs to
        // is somehow not here, just continue the loop
        if(place == nil)
            continue;

        PlaceAdjustments *place_adjustments = [PlaceAdjustments MR_createEntity];
        place_adjustments.parking = @([[adjustmentParams objectForKey:@"parking"]integerValue]);
        place_adjustments.elevator = @([[adjustmentParams objectForKey:@"elevator"]integerValue]);
        place_adjustments.toilet = @([[adjustmentParams objectForKey:@"toilet"]integerValue]);
        place_adjustments.ramp = @([[adjustmentParams objectForKey:@"ramp"]integerValue]);
        place_adjustments.availability = @([[adjustmentParams objectForKey:@"availability"]integerValue]);
        [place setPlace_adjustments:place_adjustments];
    }
    [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
}

+ (void)synchronizeCategories:(NSDictionary*)placeCategoryParams
{
    for(id categoryParams in placeCategoryParams)
    {
        NSNumber* categoryId = @([[categoryParams objectForKey:@"category_id"] integerValue]);
        NSNumber* placeId = @([[categoryParams objectForKey:@"place_id"]integerValue]);
        NSNumber* isDeleted = @([[categoryParams objectForKey:@"is_deleted"] integerValue]) ;
        Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:placeId];
        if(isDeleted.integerValue > 0){
            PlaceCategories *cat = [PlaceCategories MR_findFirstWithPredicate:[NSPredicate predicateWithFormat:@"place_id = %@ AND category_id = %@",placeId, categoryId]];
            if(cat)
                [cat MR_deleteEntity];
            } else {
            PlaceCategories *cat = [PlaceCategories MR_createEntity];
            cat.category_id = categoryId;
            cat.place_id = placeId;
            cat.place = place;
        }

    }
    [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
}

+ (void)synchronizeTags:(NSDictionary*)placeTagParams
{
    for(id placeTag in placeTagParams)
    {
        NSNumber* tagId = @([[placeTag objectForKey:@"id"]integerValue]);
        NSNumber* placeId = @([[placeTag objectForKey:@"place_id"] integerValue]);
        NSNumber* isDeleted = @([[placeTag objectForKey:@"is_deleted"] integerValue]);

        Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:placeId];
        if(isDeleted.integerValue == 1){
            PlaceTags *tag = [PlaceTags MR_findFirstWithPredicate:[NSPredicate predicateWithFormat:@"place_id = %@ AND tag_id = %@",placeId, tagId]];
            if(tag)
                [tag MR_deleteEntity];

        } else {
            PlaceTags *tag = [PlaceTags MR_createEntity];
            tag.tag = [placeTag objectForKey:@"tag"];
            tag.place_id = placeId;
            tag.place = place;
        }

    }
    [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
}
从第一行代码到

 [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) {

            [[NSNotificationCenter defaultCenter]postNotificationName:SYNCHRONIZATION_COMPLETE object:nil];

        }];
大约是一分钟的时间

如何对此进行优化?将其插入MySQL只需一秒钟。 谢谢你的关注

编辑1

经过一番分析后,我意识到,这是需要花费大量时间的开放时间和标签的同步


每次都会运行
MR_findFirstMatchingAttribute
。您对如何优化这一点有什么建议吗?

看起来您在主/默认上下文中做所有事情。这本质上是主线程上下文。通过调用saveOnlySelfAndWait,您正在阻塞主线程。这可能会导致一些同步锁定。我建议创建一个全新的背景上下文,并在那里执行所有保存

您可以发布获取和保存核心数据的仪器跟踪吗?时间配置文件也会有帮助。也许第一步是查看核心数据的文档,并在quellish see my update中对大部分数据执行批插入。谢谢