如何提高核心数据性能?

How to improve Core Data performance?

提问人:Joshua 提问时间:8/16/2010 更新时间:9/21/2013 访问量:7195

问:

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

问题是搜索栏击键滞后得很厉害......肯定是因为获取速度慢。任何如何提高性能的想法?

我的核心数据由包含 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 性能 nspredicate

评论


答:

2赞 rano 8/16/2010 #1

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

4赞 cobbal 8/16/2010 #2

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

评论

1赞 tc. 8/16/2010
+1 但请记住一次只执行一个后台查询,并获取每个查询的最新搜索字符串(或以其他方式合并文本字段更新),并降低线程/NSOperation 优先级,直到 UI 执行良好。
0赞 Joshua 8/16/2010
谢谢你的提示。我真的在努力避免多线程解决方案,但如果别无选择,我会这样做。
-1赞 Stephan Eggermont 8/16/2010 #3

启动应用程序时,请建立完整的尝试,并在编辑时进行调整。不要使用那个愚蠢的谓词。您只获取 1000 条记录,因此应该不需要时间。

评论

0赞 Joshua 8/16/2010
抱歉,我不确定如何在应用程序启动时构建完整的尝试。我真的可以提前构建这样的标题\作者尝试吗?
0赞 Stephan Eggermont 8/16/2010
只需将其构建在 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
0赞 rano 8/17/2010
最好不要完全构建它,而是按照我在回答中建议的增量构建它。
0赞 Stephan Eggermont 8/18/2010
SQLite可能很慢,但它不会慢到启动时无法读取两个字段的1000条记录,不是吗?否则,我会认真推荐使用真正的数据存储。
0赞 Stephan Eggermont 8/18/2010
对于 iPhone 应用来说,在查询时以增量方式进行构建不是可用的解决方案。您需要在第一时间快速获得结果。
18赞 Amy Worrall 8/16/2010 #4

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

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

词>“术语”和词<“燕鸥”

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

Apple 有一个 Core Data WWDC 会议来解释这一点,包括示例代码。示例代码包含一个类,该类处理字符串的规范化(即删除大小写),并以 unicode 感知方式递增单词的最后一个字符。

评论

0赞 Joshua 8/16/2010
这是一个很好的解决方案!谢谢!!如果我能找到它,我会寻找那个会话并将其发布在这里。
1赞 Ben Groot 9/29/2011
直接链接: developer.apple.com/itunes/... 嗯..我等了很久才等到你的帖子。与此同时,我找到了我自己,在互联网上挣扎:D它位于“WWDC 2010,优化iPhone OS上的核心数据性能”,时间为35:06
1赞 Obiwahn 11/5/2012
对不起,我找不到相关的示例代码(而且我是注册开发人员)。你能提供一个被截断的短代码吗?(归一化和字符增量)
0赞 Kudit 12/3/2013
当我将所有单词拉出到一个单独的实体中时,这将如何工作?我目前正在使用谓词“ANY words.word BEGINSWITH %@”,但它仍然比我想要的要慢得多。
0赞 Daniel Rinser 5/7/2014
经过一段时间的搜索,我终于找到了引用的WWDC会话示例代码(参见方法,尤其是)。:-)normalizeString:upperBoundSearchString:
13赞 Marcus S. Zarra 8/18/2010 #5

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

只有在搜索字段中键入的第一个字母才能命中磁盘。在第一个字母之后,您应该只细化内存中已有内容的搜索结果。

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

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

评论

1赞 Joshua 8/18/2010
嗨,马库斯,这是非常有趣的观点。但我认为这个解决方案存在问题。单击“a”或“e”作为第一个字母,可能会从数据库中获取大部分对象(如果不是全部)。在处理大型数据库时,这种单次提取可能需要很长时间,更不用说内存影响了......
0赞 Marcus S. Zarra 8/19/2010
无论您使用哪种实现,这种情况都不会改变。Core Data 将拉入骨架,因此内存使用率将尽可能低。当您过滤时,内存使用率会下降。该解决方案绝对有效,因为我已经多次使用它。
0赞 Mundi 11/16/2012
@MarcusS.Zarra 说得好,Marcus,但是如何使用 NSFetchedResultsController 做到这一点呢?该属性是只读的...fetchedObjects
1赞 Marcus S. Zarra 11/17/2012
当每个字符被按下时,你从中过滤,然后你的表视图读出生成的数组。您永远不需要转到磁盘,因为您已经在 中拥有所有可能的结果。我不会使用第二个.-fetchedObjectsNSFetchedResultsControllerNSFetchedResultsControllerNSFetchedResultsController