使用NSFetchedResultsController搜索每个字符CoreData是非常缓慢的大量记录
我有一个20000条记录的预加载数据库。使用NSFetchedResultsController搜索每个字符CoreData是非常缓慢的大量记录
基本上有两个实体进行搜索,City Entity
和另一个是street Entity
。市有“名称”属性和Street Entity
也有名称属性,city and street
都在one-to-many relationship
。一个城市可以有很多街道。
现在,当用户可以搜索任何字符,如“a或b”任何东西,它应该显示用户相应的城市和/或街道.Eveytime我必须重新加载和重新配置NSFetchedResultsController。
我实施了NSPredicate
来过滤记录。
let predicate = NSPredicate(format:"(name CONTAINS[c] %@) OR (SELF.streets.name CONTAINS[c] %@)",text,text)
predicateArray.append(predicate)
这个谓词用于过滤的records.I'm也使用MagicalRecord在coreData.The的包装搜索曾经是很为我在寻找每一个字符。
任何帮助将非常感激。
由于您正在处理如此庞大的数据库,因此索引数据库可能是一个好主意。
这应该会提高搜索速度,因为您只需查看索引来查找匹配项,而不必每次查看数据库中的所有20,000条记录。把它看作是在书的索引中查找某些东西,而不是阅读每一页来找到你要找的东西。
在iOS的核心数据已索引内置的。尝试启用它要被索引,看看有没有什么帮助加快您的搜索时间的属性。
Simo感谢您的快速反馈,我已将该属性编入索引,但仍需要4-5秒才能显示数据。由于城市和街道之间也存在一对一的关系,因此需要花费大量时间进行搜索。 – user1068810
在这种情况下,您应该考虑优化您的获取请求。这里有一些很好的领域:https://artandlogic.com/2013/01/optimizing-core-data-searches-and-sorts/ – Simo
仍然搜索很慢。 – user1068810
我试图做的过滤器在内存20000行。它超快!根本没有滞后。看来你要持久存储不止一次,这是我的建议:
- 使用
NSFetchedResultController
(这样做尝试第三点之前,它可以工作) - 创建两个
NSFetchRequest
停止:一个他们会给你城市,另一个会给你的街道。所以你会得到一系列的城市和街道阵列。 这种方法将帮助您避免提取效率非常低的关系city.streets
。如果可以将两者组合并映射到单个字符串数组,则更好。 -
非常重要:设置
request.returnsObjectsAsFaults = false
。否则,您将继续前往数据库以获取city.name或street.name。
当搜索文本框的变化:
- 筛选首先将城市然后在街上。
- 重新加载
tableView
编辑:试验例 我测试下面的代码
iPhone 6:100毫秒-170ms之间的第一个字符。然后它变得更快。 (2x)我没有感觉到任何滞后。
-
iPad mini 2:第一个字符在300ms-350ms之间。然后它变得更快。 (2个)有一些滞后。
class ViewController: UIViewController, UISearchBarDelegate, UITableViewDataSource{ @IBOutlet weak var tableView: UITableView! @IBOutlet weak var searchBar: UISearchBar! var streets = [Street]() var cities = [City]() var filteredStreets: [Street] = [] var filteredCities: [City] = [] override func viewDidLoad() { super.viewDidLoad() cities = findAllCities() streets = findAllStreets() filteredCities = cities filteredStreets = streets } func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { filterItemsWithCurrentSearchText(searchText) } func filterItemsWithCurrentSearchText(text: String){ if text.isEmpty { filteredStreets = streets filteredCities = cities } else { NSLog("1") filteredStreets = streets.filter{ $0.name.rangeOfString(text, options: .CaseInsensitiveSearch) != nil } NSLog("2") filteredCities = cities.filter{ $0.name.rangeOfString(text, options: .CaseInsensitiveSearch) != nil } NSLog("3") } tableView.reloadData() NSLog("4") } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return filteredStreets.count + filteredCities.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell")! if indexPath.row < filteredCities.count{ cell.textLabel!.text = "City:" + filteredCities[indexPath.row].name }else{ cell.textLabel!.text = "Street:" + filteredStreets[indexPath.row-filteredCities.count].name } return cell } func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } func findAllCities() -> [City]{ let request = City.MR_createFetchRequest() request.returnsObjectsAsFaults = false return City.MR_executeFetchRequest(request) as! [City] } func findAllStreets() -> [Street]{ let request = Street.MR_createFetchRequest() request.returnsObjectsAsFaults = false return Street.MR_executeFetchRequest(request) as! [Street] } }
好吧,我会单独去城市和街道,但我必须在名单上的城市第二次访问将返回街道,然后要么我将不得不再次从街道上取城市,因此再次是一个时间采取任务。 – user1068810
另外我试图单独抓取,但仍然很慢,至少1.5秒。 – user1068810
你可以分享代码吗?当你分别获取街道和城市时是否放置了returnObjectAsFaults? – ELKA
您可以尝试使用下面的选项来提高获取的速度。
在你的情况下,下面可能有助于更快地检索结果,
- fetchBatchSize:设置一个批次大小限制是从数据存储在一个时间检索的数据量。如果对于结果集1,000,批量大小设置为20,那么结果数组将只填充20个。当我们迭代过20时,下一批将被检索。:
下,如果万一你需要
- fetchLimit可用于有时候我们只需要对象的具体金额退还。这在有很多对象时很有用。直到提取完成才会更新UI,因此限制提取是必要的。
,具体参考:CoreData
为什么你的搜索中包含的,而不是开头?为什么允许用单个字母搜索?你在后台线程上运行搜索吗?如果用户继续输入,是否添加了逻辑以防止搜索运行?看起来你正在创造一些东西,担心大多数人不会有的问题...... – Wain
我有使用包含关键字和单字母搜索的要求。 – user1068810