2016-09-22 70 views
1

我目前正在使用coredata爲我的項目。但是,當API返回應用程序需要更新的54000個對象時,用戶必須等待近2個小時。 這是當前項目的主要問題,我正在考慮使用sqlite而不再使用coredata來更新數千個對象。Sqlite或核心數據更新更多然後50000記錄

使用Sqlite是否是正確的決定還是CoreData有任何建議?我無法決定。任何幫助都會很棒。謝謝。

下面是我在做什麼:

NSManagedObjectContext *privateObjectContext = [AppDelegate appDelegate].privateManagedObjectContext; 
    [privateObjectContext performBlock:^{ 

     int i = 1; 
     for (NSDictionary *item in itemlist) { 
      i++; 

      [fetchRequest setPredicate:[NSPredicate predicateWithFormat: 
             @"itemID == %@",[item objectForKey:@"item_id"] 
             ]]; 
      NSError *error; 
      NSMutableArray *inventories = [[NSMutableArray alloc]initWithArray: 
              [privateObjectContext executeFetchRequest:fetchRequest 
                       error:&error]]; 
      ItemManagedObject *itemMO; 

      if(inventories.count){ 
       itemMO = inventories.firstObject; 
      }else{ 
       itemMO = [NSEntityDescription insertNewObjectForEntityForName:@"ItemObject" 
                 inManagedObjectContext:privateObjectContext]; 
      } 
      [itemMO prepareWithDictionary:item]; 
     } 

     NSError *error; 
     if (![privateObjectContext save:&error]) { 
      completionHandler(NO); 
     } 
} 
+0

你能描述一下你當前如何更新對象,這需要將近2個小時嗎?可能有辦法改進它,但是不可能說如果不知道你現在在做什麼。 –

+0

是的,我們需要更多的細節,你如何處理更新,你多久保存一次上下文,你是否使用儀器來尋找瓶頸,發佈一些代碼 – trapper

+0

@TomHarrington我添加了代碼。 – mega90

回答

0

2小時很長。這很奇怪。

然而,您可以通過讓核心數據做更少的工作來按摩您的代碼。更少的工作。

  1. 執行單一讀取請求而不是54K提取請求
  2. 不要調用託管對象的屬性設置當屬性值不會改變,所以沒有對象被不必要地標記爲髒,並且在調用「保存」方法時,核心數據不必執行昂貴但無用的對象更新。

這將顯着減少Core Data執行的工作量和應用程序的性能。

第二點很簡單,但非常冗長:在調用setters之前,比較每個單獨的屬性值與字典值。

第一點需要一種算法變化:

執行單讀取請求時,通過編號的順序排列(與[NSFetchRequest setSortDescriptors:])

排序字典由ID(與[NSArray的sortedArray ...] )

同步兩個排序列表(這是最重要的兩個列表排序):

NSEnumerator *itemMOEnum = [itemMOs objectEnumerator]; 
NSEnumerator *dicEnum = [dictionaries objectEnumerator]; 
ItemManagedObject *itemMO = [itemMOEnum nextObject]; 
NSDictionary *itemDic = [dicEnum nextObject]; 

while (itemDic) { 
    NSComparisonResult comparison = itemMO ? [itemDic[@"item_id"] compare:itemMO.itemID] : NSOrderedAscending; 
    switch (comparison) { 
     case NSOrderedSame: 
      // id present in both lists: update 
      [itemMO prepareWithDictionary:itemDic]; 

      itemMO = [itemMOEnum nextObject]; 
      itemDic = [dicEnum nextObject]; 
      break; 

     case NSOrderedAscending: { 
      // id present only in dictionaries: create 
      itemMO = [NSEntityDescription insertNewObjectForEntityForName:@"ItemObject" 
              inManagedObjectContext:privateObjectContext]; 
      [itemMO prepareWithDictionary:itemDic]; 

      itemDic = [dicEnum nextObject]; 
     } break; 

     case NSOrderedDescending: 
      // id present only in managed object: delete or do nothing 
      itemMO = [itemMOEnum nextObject]; 
      break; 
    } 
} 

while (itemMO) { 
    // id present only in managed object: delete or do nothing 
    itemMO = [itemMOEnum nextObject]; 
} 

和保存。

最後,也許SQLite的速度會更快(見https://github.com/groue/GRDB.swift/wiki/Performance對於試圖在比較核心數據的使用SQLite庫的性能)。

但SQLite的不會變成一個緩慢的算法成一快一

+0

謝謝soo。它需要7分鐘。我從來沒有想過使用NSEnumerator。抱歉遲了迴應。 – mega90

0

我從來沒有在sqlite的重做核心數據項目,反之亦然。所以我不能告訴你是否有性能差異/

然而,54k = 2小時的事情聽起來很奇怪。你談論的是一個API,它讓我懷疑涉及服務器,你的問題是關於數據庫。當然,2小時聽起來太長了,讓我懷疑你的數據庫的核心設計是否有問題。例如,缺乏索引。根據您的查詢和數據庫,單個更新可能會觸發各種重型處理。

另一種是你爲什麼要處理設備上的這一列數據。需要處理很多事情,我想知道是否有辦法減少音量,選擇性地進行更新,或者甚至更好 - 將其移動到服務器。

我認爲你需要重新考慮你的問題。提供關於數據庫的更多上下文,正是你在做什麼以及爲什麼。

+0

就像@ jrturton說的那樣:「如果itemList包含54,000個對象,那麼您將對持久存儲執行54,000次提取,以便每次檢查一個ID。」 。我不知道這個coredata的工作系統。我想2小時的答案是這樣的。 – mega90

0

CoreData不是數據庫管理器,而是對象圖和持久性管理器。 CoreData可以將其對象存儲在sqlite數據庫中,也可以存儲在XML文件或二進制文件中(開發人員可以選擇最適合其需求的選項)。

CoreData和數據庫管理器之間的主要區別在於,要訪問CoreData的對象,CoreData需要實例化Objective-C/Swift對應的對象。

Sqlite可以訪問部分數據,而無需提取包含數據的完整記錄。然後,CoreData需要維護對象之間的關係圖(2個CoreData類之間的關係,並且通常以兩種方式)。

因此,當更新54k對象時,您要求CoreData實例化54k對象(在內存中)並最終更新它們的關係。

對於移動設備上的CoreData來說這是非常繁重的工作。

也許您的CoreData模型未正確優化。 也許您應該定期保存CoreData上下文並刷新CoreData暫存器(包含實際讀取或更新對象的內存部分)。

但以我的經驗,CoreData不適合繁重的數據工作。

如果你想能夠從sqlite記錄中重新實例化你的classe對象並管理相當自動的關係,但是它是可行的,那麼用sqlite重新實現你的需求可能是一些工作。我在一些項目上做過。這增加了一個模型對象的好處,例如,可以在Android平臺上與其他平臺更加共享模型對象,因爲sqlite在許多平臺上都可用。

還有一件事:sqlite更適合從多個線程使用。 CoreData對此更加敏感,並且需要線程一個上下文,最終還需要一些上下文同步。

+0

感謝您的解釋,現在我更好地理解核心數據和sqlite差異。有時候更好地詢問並獲得更多意見來理解問題並學習東西,然後在網上搜索並嘗試獲得一個想法(我搜索了,但現在我更好地理解了) – mega90

1

核心數據提供NSBatchUpdateRequest它允許你直接作出的持久性存儲更新,而無需在內存中涉及實例和處理的管理對象。

您應該使用核心數據性能工具來運行此代碼。如果itemList包含54,000個對象,那麼您將對持久性存儲執行54,000次提取,以每次檢查一個ID。要提前獲取所有ID,然後檢查內存中的結果比執行重複提取請求要快得多 - 原始SQL中的代碼幾乎與核心數據中的代碼一樣慢。

此代碼看起來也錯了:

ItemManagedObject *itemMO; 

if(itemMO.count){ 

它永遠不會通過,如果測試,除非你已經錯過了線的地方。

+0

ups.while我編輯我的代碼爲stackoverflow問題,我寫錯了。但每個3或4列可以有不同的值。非他們是一樣的。所以NSBatchUpdateRequest對這種情況是沒用的。但是,無論如何,謝謝。有了答案,我學到了更多關於sqlite coredata與更好解釋之間的區別。因此,將結構轉換爲使用來自coredata的sqlite會很好。 – mega90