2011-09-01 73 views
7

我的iPhone應用程序具有實體Words,屬性word,lengthlanguage。兩者都被編入索引: Entity and attributes簡單核心數據提取非常緩慢

我將cdatamodel和數據庫複製到一個單獨的導入器應用程序,在該應用程序中預填了大約400k字的不同語言。我通過查看SQLite文件來驗證導入,然後將預填充的數據庫複製回iPhone項目。

首先我認爲(簡單)謂詞是問題。但是,即使在讀取請求刪除謂語之後,它需要很長的時間來執行:

2011-09-01 09:26:38.945 MyApp[3474:3c07] Start 
2011-09-01 09:26:58.120 MyApp[3474:3c07] End 

這裏是我的代碼如下所示:

// Get word 
NSLog(@"Start"); 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Words" inManagedObjectContext:appDelegate.managedObjectContext]; 
[fetchRequest setEntity:entity]; 

NSError *error = nil; 
NSArray *fetchedObjects = [appDelegate.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 
if (fetchedObjects == nil) { 
    //... error handling code 
} 

[fetchRequest release]; 
NSLog(@"End"); 
return fetchedObjects; 

是條目的數據庫中的數核心數據的問題?


編輯: 作爲gcbrueckmann和jrturton指出,這是一個好點的設置fetchBatchSize。但取時間仍然是不令人滿意的:

  • 2秒謂詞組:

    NSPredicate *謂詞= [NSPredicate predicateWithFormat:@ 「長度==%d與語言BEGINSWITH%@」,字長,LNG ]。 [fetchRequest setPredicate:predicate];

  • 7秒與批料尺寸集:

    [fetchRequest setFetchBatchSize:1];

  • 1與謂詞和批量大小都第二套

是否還有另一個瓶頸?

+0

在你的謂詞是語言可能比長度更嚴格,謂詞檢查有時爲了能夠加快速度爲好。例如在這種情況下,如果有60%的單詞符合您的長度標準,但只有40%符合語言標準,最好先進行語言檢查。另一件事可能是,如果你需要更快的速度將是它預先加載,然後過濾內存中的數組不知道如果你的iPhone應用程序可以處理,但。 –

+0

在這種情況下,第一個查詢是比較整數(索引將使這非常快),第二個是字符串比較(即使索引字符串不會很快) - 如果重新排序查詢幫助,我會感到驚訝。但是,請嘗試一下 - 我有興趣看看它是否有幫助! – deanWombourne

+0

哦,我忘了提及它:我已經試圖交換謂詞的順序,它不會加快取回。 – Norbert

回答

11

由於您不以任何方式限制結果集,所以一次獲取400,000個對象肯定會成爲Core Data的負擔。有幾種方法可以提高性能:

更改提取請求的fetchBatchSize限制了提取一次保留在內存中的對象數。此功能對您的應用程序完全透明,所以絕對值得一試。

如果您不需要完整的對象,則可以考慮將獲取請求的resultType更改爲更合適的值。特別是如果您只對某個對象的某些值感興趣,則使用NSDictionaryResultType是個不錯的主意。

最後fetchLimitfetchOffset屬性允許您限制結果範圍,如果你想自己管理批處理。如果您對每個結果對象的處理使用大量內存,這是一個不錯的主意,因爲您可以將每個批次打包到NSAutoreleasePool(只是不要試圖爲每個結果對象創建一個自動釋放池)。

我猜1秒。可能就像你的情況一樣快 - 即使你使用普通的Sqlite數據庫。我能想到的唯一進一步的優化是爲每種語言使用一個表格(而不是將所有語言的單詞放入單個表格中)。當然,這隻適用於Sqlite,除非您爲所有語言定義單獨的實體,即i。即按原樣取出你的Words實體並將其抽象化。然後添加像EnglishWord等子實體。來自不同實體的對象存儲在單獨的表中。因此,結合fetchBatchSizepredicate參數,這應該與Sqlite方法類似地執行,對於所有語言都使用單獨的表。

+0

'fetchBatchSize'絕對是一個好點。但不幸的是,它仍然需要2秒來抓住一個字。 – Norbert

+0

在你的情況下使用的是一個裸骨骼Sqlite數據庫的選項嗎?它看起來像現有的對象沒有修改,所以核心數據可能不會有任何優於普通Sqlite的優勢。 400,000真的是iPhone上的一個大型數據集。每種語言都有一個表是否可以選擇? – gcbrueckmann

+0

是的,我已經想過切換回普通的SQLite,但我認爲仍然可能存在一個我看不到的瓶頸。 – Norbert

1

這會將您的完整400k數據庫存入內存,看起來好像很多。你可以調查其停止框架返回完整對象的一切在你的讀取請求時,在您不需要每次返回的對象從店在第一時間獲取的假設NSFetchRequest的

setFetchBatchSize 

方法。

2

你在做BEGINSWITH - 這不是一個非常快的操作!但是,語言數量有限,所以emum可能會有所幫助。

有一個language_id字段,它是一個索引整數並在謂詞中使用它。您仍然可以保存語言的名稱,以及,並返回其作爲獲取對象的一部分,只是不搜索就可以了:)


PS您可以通過添加「-com.apple打開SQL調試。 CoreData.SQLDebug 1'作爲啓動時傳遞的參數(在您的Scheme中配置此參數) - 這可能有助於您瞭解SQL在幕後做了些什麼。

(見this question瞭解詳細信息)

+0

'語言BEGINSWITH%@'耗時600毫秒(平均); 'language ==%@'花了350ms(平均)! – Norbert

+1

我相信在這些方面我也看到它說要像比較語言> =%@那樣做比使用BEGINSWITH更快。我想說這是在2010年WWDC核心數據視頻中。 –

+0

如果這仍然是字符串相等,那麼如果轉換爲比較整數,則會得到更多的加速;)SQL中的字符串索引只考慮字符串中的一定數量的字符,而索引整數是理想的! - http://dev.mysql.com/doc/refman/5.0/en/create-index.html – deanWombourne