2016-11-04 50 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

相關問題