2016-11-04 52 views
0

我有一个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的包装搜索曾经是很为我在寻找每一个字符。

任何帮助将非常感激。

+0

为什么你的搜索中包含的,而不是开头?为什么允许用单个字母搜索?你在后台线程上运行搜索吗?如果用户继续输入,是否添加了逻辑以防止搜索运行?看起来你正在创造一些东西,担心大多数人不会有的问题...... – Wain

+0

我有使用包含关键字和单字母搜索的要求。 – user1068810

回答

0

由于您正在处理如此庞大的数据库,因此索引数据库可能是一个好主意。

这应该会提高搜索速度,因为您只需查看索引来查找匹配项,而不必每次查看数据库中的所有20,000条记录。把它看作是在书的索引中查找某些东西,而不是阅读每一页来找到你要找的东西。

Database indexing - Wikipedia

在iOS的核心数据已索引内置的。尝试启用它要被索引,看看有没有什么帮助加快您的搜索时间的属性。

Core Data attribute indexing

+0

Simo感谢您的快速反馈,我已将该属性编入索引,但仍需要4-5秒才能显示数据。由于城市和街道之间也存在一对一的关系,因此需要花费大量时间进行搜索。 – user1068810

+0

在这种情况下,您应该考虑优化您的获取请求。这里有一些很好的领域:https://artandlogic.com/2013/01/optimizing-core-data-searches-and-sorts/ – Simo

+0

仍然搜索很慢。 – user1068810

1

我试图做的过滤器在内存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] 
    } 
    } 
    
+0

好吧,我会单独去城市和街道,但我必须在名单上的城市第二次访问将返回街道,然后要么我将不得不再次从街道上取城市,因此再次是一个时间采取任务。 – user1068810

+0

另外我试图单独抓取,但仍然很慢,至少1.5秒。 – user1068810

+0

你可以分享代码吗?当你分别获取街道和城市时是否放置了returnObjectAsFaults? – ELKA

0

您可以尝试使用下面的选项来提高获取的速度。

在你的情况下,下面可能有助于更快地检索结果,

  • fetchBatchSize:设置一个批次大小限制是从数据存储在一个时间检索的数据量。如果对于结果集1,000,批量大小设置为20,那么结果数组将只填充20个。当我们迭代过20时,下一批将被检索。:

下,如果万一你需要

  • fetchLimit可用于有时候我们只需要对象的具体金额退还。这在有很多对象时很有用。直到提取完成才会更新UI,因此限制提取是必要的。

,具体参考:CoreData