简体   繁体   English

如何提高核心数据的性能?

[英]How to improve Core Data performance?

My app has a UISearchBar allowing user to enter search keywords. 我的应用程序有一个UISearchBar,允许用户输入搜索关键字。 Each keystroke executes a Core Data query in order to display the results as text in search bar changes. 每次击键都会执行核心数据查询,以便将结果显示为搜索栏更改中的文本。

The problem is that search bar keystrokes are lagging pretty bad... surely because of slow fetching. 问题是搜索栏击键非常糟糕......当然是因为提取速度慢。 Any ideas how to improve the performance? 任何想法如何提高性能?

My Core Data is backed with sqlite data store which contains 1000 objects. 我的核心数据由sqlite数据存储支持,其中包含1000个对象。

// 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];

Using CONTAINS slows it down. 使用CONTAINS可以减慢它的速度。 What you need to do is create a new table called searchWords (or whatever), and in that store all the words within your titles, made lower case and with accents removed. 您需要做的是创建一个名为searchWords(或其他)的新表,并在该商店中标题中的所有单词,小写并删除重音。 These have a relationship linking them back to the original objects. 这些关系将它们链接回原始对象。 Make sure the word field is indexed. 确保单词字段已编入索引。

Perform your query on this table, but instead of using CONTAINS or BEGINSWITH, do something like 在此表上执行查询,但不要使用CONTAINS或BEGINSWITH,而是执行类似的操作

word > "term" AND word < "tern" 单词>“term”和单词<“tern”

Note that the first string in there is the search term, and the second is the search term with the last character incremented. 请注意,其中的第一个字符串是搜索项,第二个字符串是最后一个字符递增的搜索项。 This allows Core Data to use the SQL index to perform the search. 这允许Core Data使用SQL索引来执行搜索。

Apple have a Core Data WWDC session that explains this, including sample code. Apple有一个核心数据 WWDC会话,解释了这一点,包括示例代码。 The sample code contains a class that handles normalising the string (Ie Removing case), and incrementing the last character of a word in a unicode aware way. 示例代码包含一个类,该类处理规范化字符串(即删除大小写),并以unicode感知方式递增单词的最后一个字符。

While Amoyra's recommendation is sound, you also have a design issue. 虽然Amoyra的推荐是合理的,但您也有设计问题。

Only the first letter typed into the search field should ever hit the disk. 只有输入到搜索字段中的第一个字母应该永远打盘。 After the first letter you should only be refining the search results of what is already in memory. 在第一个字母之后,您应该只改进已经在内存中的搜索结果。

You should filter the array that is in memory (from the first letter search) using the predicate you already have and avoid executing a fetch request as it is unnecessary. 您应该使用已有的谓词过滤内存中的数组(从第一个字母搜索),并避免执行获取请求,因为它是不必要的。

In addition, if you are going to search on data that is already in memory (such as living in a NSFetchedResultsController ) then your entire search should only hit the objects in memory. 此外,如果要搜索已经在内存中的数据(例如生活在NSFetchedResultsController ),那么整个搜索应该只搜索内存中的对象。 Going out to disk is unnecessary and terribly wasteful. 走向磁盘是不必要的,非常浪费。

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

You can create a trie incrementally in order to have an index for past queries (result sets are pointed by the leaf nodes). 您可以逐步创建trie ,以便为过去的查询创建索引(结果集由叶节点指向)。 but it won't increase the performance of a single query. 但它不会增加单个查询的性能。 You can also tweak the keystroke system, don't do a fetch after each single keystroke but only after a keystroke after which a time interval (as a threshold) passed before another keystroke is recognized 你也可以调整击键系统,不要在每次击键后进行提取,但只有在击键之后才能获得一个时间间隔(作为一个阈值),然后再识别另一个击键

When starting the app, build up a full trie, and adapt it when editing. 启动应用程序时,构建完整的trie,并在编辑时进行调整。 Do not use that stupid predicate. 不要使用那个愚蠢的谓词。 You're only fetching a 1000 records, so that should take no time. 你只需要获取1000条记录,所以这应该不花时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM