优化此核心数据请求

Posted

技术标签:

【中文标题】优化此核心数据请求【英文标题】:Optimizing this Core Data request 【发布时间】:2013-04-09 13:05:08 【问题描述】:

我在 Core Data 中有一个名为 MusicInterest 的实体。我必须一次添加 5000 个左右,我当前的过程是查询 MusicInterest 是否已经存在,如果不创建一个新的。

这似乎需要去商店 5000 次才能查看每个标题是否存在。当然,还有插入行程,但 5000 次查询让我慢了下来。

每个 FacebookFriend 都会有多个音乐兴趣,我使用一组字符串标题枚举每个人,调用以下代码。

任何想法如何优化这个?

+ (MusicInterest*) musicInterestForFacebookFriend:(FacebookFriend*)facebookFriend WithTitle:(NSString*)musicTitle UsingManagedObjectContext:(NSManagedObjectContext*)moc

    // query to see if there
    NSArray *matches = [self queryForMusicTitle:musicTitle moc:moc];

    if (([matches count] >= 1)) 
        // NSLog(@"Music already in database");
        MusicInterest *existingMusic = [matches lastObject];
        [existingMusic addLikedByObject:facebookFriend];
        return [matches lastObject];
     else 
        // create new Music Interest
        MusicInterest *newMusic = [NSEntityDescription insertNewObjectForEntityForName:@"MusicInterest" inManagedObjectContext:moc];
        newMusic.title = musicTitle;
        [newMusic addLikedByObject:facebookFriend];
        return newMusic;
    


+ (NSArray *)queryForMusicTitle:(NSString *)MusicTitle moc:(NSManagedObjectContext *)moc

    // query to see if there
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"MusicInterest"];
    request.predicate = [NSPredicate predicateWithFormat:@"title == %@", [NSString stringWithFormat:@"%@", MusicTitle]];

    NSError *error = nil;
    NSArray *matches = [moc executeFetchRequest:request error:&error];
    if (error) 
        NSLog(@"Error querying title in Music interest. Error = %@", error);
    
    return matches;

更新:

我采用了 Core Data 编程指南中建议的设计,它将我的时间从 12 秒减少到 4 秒(在其他方面仍需要一些优化:)

该指南仅包含一半示例代码 - 我想我会分享我的完整实现:​​

musicArray = [[music componentsSeparatedByString:@", "] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) 
                if (obj1 > obj2)
                    return NSOrderedDescending;
                else if (obj1 < obj2)
                    return NSOrderedAscending;
                return NSOrderedSame;
            ];

            if (musicArray) 

                NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"MusicInterest"];
                [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"title IN %@", musicArray]];
                [fetchRequest setSortDescriptors:
                 @[[[NSSortDescriptor alloc] initWithKey: @"title" ascending:YES]]];

                NSError *fetchError = nil;
                NSArray *musicInterestMatchingTitles = [backgroundContext executeFetchRequest:fetchRequest error:&fetchError];

                if ([musicArray count] > 0) 
                    // walk musicArray and musicInterestsMatchingTitles in parallel
                    for (int i = 0; i < [musicArray count]; i++) 
                        NSString *title = musicArray[i];
                        if (i < [musicInterestMatchingTitles count]) 
                            MusicInterest *comparingMusicInterest = musicInterestMatchingTitles[i];
                            // compare each title
                            if (![title isEqualToString:comparingMusicInterest.title]) 
                                // if it doesn't exist as a ManagedObject (a MusicInterest), create one
                                MusicInterest *musicInterest = [MusicInterest createNewMusicInterestUsingManagedObjectContext:backgroundContext];
                                musicInterest.title = title;
                                [musicInterest addLikedByObject:friend];
                             else 
                                // otherwise, just establish the relationship
                                [comparingMusicInterest addLikedByObject:friend];
                            
                         else 
                            // if there are no existing matching managedObjects, create one
                            MusicInterest *musicInterest = [MusicInterest createNewMusicInterestUsingManagedObjectContext:backgroundContext];
                            musicInterest.title = title;
                            [musicInterest addLikedByObject:friend];
                        
                    
                
            

        ];
        [self saveBackgroundContext:backgroundContext];

【问题讨论】:

看起来你已经有了一个很好的答案,但这里有一个小提示:给定一个字符串 MusicTitle[NSString stringWithFormat:@"%@", MusicTitle] 什么都不做。 嗯,它确实给了你一个 MusicTitle 的字符串 :) 是的,但该字符串与 MusicTitle 具有相同的内容。如果您明确想要一份副本,请使用 [MusicTitle 副本]。但是 NSPreficate 无论如何都会复制传递给它的字符串的内容,所以这个复制是多余的。 另外,按照惯例,方法参数以小写字母开头。 (musicTitle,而不是 MusicTitle。)目前,您的代码的工作方式相同。但是 a) 遵守约定有助于其他程序员理解您的代码,并且 b) ObjC 约定成为要求的历史(参见 KVC、ARC)。 我知道了,谢谢。只是一个错字。 【参考方案1】:

Implementing Find-or-Create Efficiently 在“核心数据编程指南”中描述了一种可能在这里有用的模式。基本思路是:

按也存储在 数据库。 执行单次获取请求,从数据库中获取所有具有列表中 id 的对象,并按相同的 id 排序。 现在并行遍历您的列表和获取的项目数组,以查找必须插入哪些项目以及哪些项目已经存在并且可以更新。

【讨论】:

谢谢,这正是我想要的 :)

以上是关于优化此核心数据请求的主要内容,如果未能解决你的问题,请参考以下文章

Web前端性能优化

Django 网站优化:对核心 python 函数的调用过多?

核心数据简单获取请求模板

浅析即时通讯移动端 IM 开发中登录请求的优化

大型数据集上的核心数据获取请求缓慢

保存核心数据中断获取请求