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

时间:2022-03-18 03:46:29

My app has a UISearchBar allowing user to enter search keywords. Each keystroke executes a Core Data query in order to display the results as text in search bar changes.

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

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

5 个解决方案

#1


18  

Using CONTAINS slows it down. 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. These have a relationship linking them back to the original objects. Make sure the word field is indexed.

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

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. The sample code contains a class that handles normalising the string (I.e. Removing case), and incrementing the last character of a word in a unicode aware way.

Apple有一个核心数据WWDC会话,解释了这一点,包括示例代码。示例代码包含一个类,该类处理规范化字符串(即删除案例),并以unicode识别方式递增单词的最后一个字符。

#2


13  

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. Going out to disk is unnecessary and terribly wasteful.

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

#3


4  

While it won't speed up the query, putting the lookup into a background thread will stop the keystrokes from lagging.

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

#4


2  

You can create a trie incrementally in order to have an index for past queries (result sets are pointed by the leaf nodes). 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

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

#5


-1  

When starting the app, build up a full trie, and adapt it when editing. Do not use that stupid predicate. You're only fetching a 1000 records, so that should take no time.

启动应用程序时,构建一个完整的trie,并在编辑时进行调整。不要使用那个愚蠢的谓词。你只获取了1000条记录,所以这应该不花时间。

#1


18  

Using CONTAINS slows it down. 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. These have a relationship linking them back to the original objects. Make sure the word field is indexed.

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

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. The sample code contains a class that handles normalising the string (I.e. Removing case), and incrementing the last character of a word in a unicode aware way.

Apple有一个核心数据WWDC会话,解释了这一点,包括示例代码。示例代码包含一个类,该类处理规范化字符串(即删除案例),并以unicode识别方式递增单词的最后一个字符。

#2


13  

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. Going out to disk is unnecessary and terribly wasteful.

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

#3


4  

While it won't speed up the query, putting the lookup into a background thread will stop the keystrokes from lagging.

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

#4


2  

You can create a trie incrementally in order to have an index for past queries (result sets are pointed by the leaf nodes). 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

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

#5


-1  

When starting the app, build up a full trie, and adapt it when editing. Do not use that stupid predicate. You're only fetching a 1000 records, so that should take no time.

启动应用程序时,构建一个完整的trie,并在编辑时进行调整。不要使用那个愚蠢的谓词。你只获取了1000条记录,所以这应该不花时间。

相关文章