【问题标题】:How to improve Core Data performance?如何提高核心数据性能?
【发布时间】:2011-03-30 04:26:56
【问题描述】:

我的应用有一个 UISearchBar 允许用户输入搜索关键字。每次击键都会执行一个 Core Data 查询,以便将结果显示为搜索栏中的文本更改。

问题是搜索栏击键非常糟糕......肯定是因为获取速度慢。任何想法如何提高性能?

我的核心数据由包含 1000 个对象的 sqlite 数据存储支持。

// searchKeyword is the string appears in UISearchBar
// Both title and author may contain several words so I can't use BEGINSWITH
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"(author CONTAINS[c] %@) OR (title CONTAINS[c] %@)", searchKeyword, searchKeyword];

NSEntityDescription* entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:managedObjectContext];

NSFetchRequest* request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setPredicate:predicate];
[request setFetchLimit:10];

NSSortDescriptor* sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
NSArray* sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];

[sortDescriptor release];
[sortDescriptors release];

execute request and fetch the results
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                managedObjectContext:managedObjectContext
                                sectionNameKeyPath:nil
                                cacheName:nil];
NSError* error = nil;
BOOL success = [fetchedResultsController performFetch:&error];
[request release];

【问题讨论】:

    标签: iphone core-data performance nspredicate


    【解决方案1】:

    使用 CONTAINS 会减慢速度。您需要做的是创建一个名为 searchWords(或其他)的新表,并在其中存储标题中的所有单词,将其设为小写并删除重音。这些具有将它们链接回原始对象的关系。确保 word 字段已编入索引。

    在此表上执行查询,但不要使用 CONTAINS 或 BEGINSWITH,而是执行类似的操作

    单词>“术语”和单词

    请注意,其中的第一个字符串是搜索词,第二个是搜索词,最后一个字符递增。这允许 Core Data 使用 SQL 索引来执行搜索。

    Apple 有一个 Core Data WWDC 会议对此进行了解释,包括示例代码。示例代码包含一个处理规范化字符串的类(即删除大小写),并以识别 unicode 的方式递增单词的最后一个字符。

    【讨论】:

    • 这是一个很好的解决方案!谢谢!!如果我能找到它,我会查找该会话并将其发布在这里。
    • 直接链接:developer.apple.com/itunes/… 嗯.. 我等你的帖子很久了。与此同时,我发现它是我自己,在互联网上苦苦挣扎:D 它在“WWDC 2010,在 iPhone OS 上优化核心数据性能”,时间为 35:06
    • 对不起,我找不到相关的示例代码(我是注册开发人员)。你能提供一个简短的代码吗? (归一化和字符增量)
    • 当我将所有单词提取到一个单独的实体中时,这将如何工作?我目前正在使用谓词 'ANY words.word BEGINSWITH %@' 但它仍然比我想要的慢得多。
    • 搜索了一段时间,终于找到了引用的WWDC sessionsample code(见方法normalizeString:,尤其是upperBoundSearchString:)。 :-)
    【解决方案2】:

    虽然 Amoyra 的建议是合理的,但您也有设计问题。

    只有在搜索字段中输入的第一个字母永远会出现在磁盘上。在第一个字母之后,您应该只优化内存中已有内容的搜索结果。

    您应该使用您已经拥有的谓词过滤内存中的数组(从第一个字母搜索),并避免执行获取请求,因为它是不必要的。

    此外,如果您要搜索内存中已经存在的数据(例如生活在NSFetchedResultsController 中),那么您的整个搜索应该只命中内存中的对象。去磁盘是不必要的,而且非常浪费。

    【讨论】:

    • 嗨,Marcus,这真的很有趣。但我认为该解决方案存在问题。单击“a”或“e”作为第一个字母,可能会从数据库中获取大部分对象(如果不是全部)。在处理大型数据库时,这个单次提取可能需要很长时间,而不是谈论内存影响......
    • 无论你使用什么实现,这种情况都不会改变。 Core Data 将引入骨架,因此内存使用量将尽可能低。当您过滤时,内存使用量会下降。该解决方案绝对有效,因为我已经使用过很多次了。
    • @MarcusS.Zarra 好点,Marcus,但是你如何使用 NSFetchedResultsController 做到这一点? fetchedObjects 属性是只读的...
    • 按下每个字符时,您从NSFetchedResultsController 中过滤-fetchedObjects,然后您的表视图读取结果数组。您永远不需要去磁盘,因为您已经在NSFetchedResultsController 中获得了所有可能的结果。我不会使用第二个NSFetchedResultsController
    【解决方案3】:

    启动应用程序时,构建一个完整的 trie,并在编辑时对其进行调整。不要使用那个愚蠢的谓词。您只获取 1000 条记录,因此应该不会花时间。

    【讨论】:

    • 抱歉,我不确定如何在应用启动时构建完整的 trie。我真的可以提前建立这样的title\author trie吗?
    • 只需在 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 中构建它
    • 最好不要完全构建它,而是按照我在回答中的建议逐步构建它。
    • SQLite 可能会很慢,但不会慢到启动时无法读取两个字段的 1000 条记录,不是吗?否则我会认真推荐使用真实的数据存储。
    • 在查询时增量构建对于 iPhone 应用程序来说不是可用的解决方案。您第一次需要快速结果。
    【解决方案4】:

    虽然它不会加快查询速度,但将查找置于后​​台线程将阻止击键滞后。

    【讨论】:

    • +1 但请记住一次只执行一个后台查询,并在每个查询上获取最新的搜索字符串(或以其他方式合并文本字段更新),并降低线程/NSOperation 优先级,直到用户界面表现不错。
    • 感谢您的提示。我真的很想避免多线程解决方案,但如果我别无选择,我会这样做。
    【解决方案5】:

    您可以增量创建trie 以便为过去的查询创建索引(结果集由叶节点指向)。但它不会提高单个查询的性能。您还可以调整击键系统,不要在每次击键后进行提取,而是仅在击键之后经过一段时间(作为阈值)之后才能识别另一个击键

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多