2011-09-01 12 views
7

私のiPhoneアプリケーションには、word,lengthおよびlanguageという属性を持つエンティティWordsがあります。両方がインデックス化されています Entity and attributesシンプルなコアデータの取り込みが非常に遅い

が、私はそれは、さまざまな言語には約400kの言葉があらかじめ入力しまった別のインポートアプリケーションにcdatamodelし、データベースをコピーしました。 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; 

は、データベース内のエントリ数ですコアデータの問題?


EDIT: gcbrueckmannとjrturtonが指摘したように、それはfetchBatchSizeを設定するには良い点です。しかし、時間はまだ不満足であるフェッチ:述語が設定されて

  • 2秒:

    NSPredicate *述語= [NSPredicate predicateWithFormat: "長さ==%dと言語BEGINSWITHの%の@" @、ワード長、LNG ]; [fetchRequest setPredicate:predicate];

    :バッチサイズが設定された

  • 7秒[fetchRequest setFetchBatchSize:1]。

  • 1述語とバッチサイズは

を設定し、両方のはまだ別のボトルネックがありますかとの二

+0

は時々述語チェックの順序が同様に物事をスピードアップすることができ、おそらくより限定的な長さよりも言語です。たとえば、この場合、単語の60%が長さ基準を満たしていて、40%だけが言語基準を満たしていれば、最初に言語チェックを行う方が良いでしょう。もう1つのことは、これを高速化する必要がある場合は、プリロードしておき、メモリー内の配列をフィルタリングして、iphoneアプリで処理できるかどうかわからない場合です。 –

+0

この場合、最初のクエリは整数を比較しています(インデックス作成は非常に速くなります)。2番目のクエリは文字列比較です(インデックス化された文字列でさえ高速にならない) - クエリを並べ替えることで助けになりました。しかし、それを試してみてください - 私はそれが助けられたかどうか見て興味があるだろう! – deanWombourne

+0

ああ、私はそれを言い忘れた:私はすでに述語の順序を交換しようとしたが、それはフェッチをスピードアップしません。 – Norbert

答えて

11

一度に400,000個のオブジェクトをフェッチしても、結果セットは決してCore Dataの負担になることはありません。パフォーマンスを向上させるには、いくつかの方法があります。は、一度にフェッチするメモリの数を制限します。この機能はアプリケーションには完全に透過的なので、試してみる価値があります。

完全なオブジェクトを必要としない場合は、フェッチ要求のresultTypeをより適切な値に変更することを検討してください。特に、オブジェクトの一部の値にのみ興味がある場合は、NSDictionaryResultTypeを使用することをお勧めします。

最後に、fetchLimitおよびfetchOffsetプロパティを使用すると、バッチ処理を自分で管理する場合は結果の範囲を制限できます。 NSAutoreleasePoolで各バッチをラップすることができるので、各結果オブジェクトの扱いが大量のメモリを使用する場合は、これが良い考えです(各結果オブジェクトごとに自動解放プールを作成したくない)。

1秒。たとえあなたが単純なSqliteデータベースに頼っていても、あなたのケースで得られるほど速くなるかもしれません。私が考えることができる唯一のさらなる最適化は、言語ごとに1つのテーブルを使用することです(すべての言語の単語を1つのテーブルに入れるのではなく)。これは、もちろん、すべての言語に対して別個のエンティティを定義しない限り、つまりSqliteでのみ機能します。 e。 Wordsエンティティをそのまま使用して抽象化してください。その後、EnglishWordなどのような下位項目を追加します。異なるエンティティからのオブジェクトは、別々のテーブルに格納されます。したがって、fetchBatchSizepredicateのパラメータを組み合わせると、これはSqliteのアプローチと同様に、すべての言語に対して別々のテーブルを使用して実行する必要があります。

+0

'fetchBatchSize'は間違いなく良い点です。しかし残念ながら、1単語をグラップするのに2秒かかる。 – Norbert

+0

ベアボーンのSqliteデータベースを使用していますか?それは既存のオブジェクトが変更されていないように見えるので、Core DataはおそらくプレーンなSqliteよりも利点がありません。 400,000は本当にiPhone上の大規模なデータセットです。言語ごとに1つの表を持つことはオプションになりますか? – gcbrueckmann

+0

はい、私はすでに普通のSQLiteに切り替えることを考えていましたが、まだ見えないボトルネックが残っていると思いました。 – Norbert

1

これは、たくさんのように見えるあなたの完全な400kデータベースをメモリにフェッチします。あなたは、あなたが最初のインスタンスでストアからフェッチするごとに返されたオブジェクトを必要としないことを前提に、フェッチ要求にすべてのための完全なオブジェクトを返すのフレームワークを停止しNSFetchRequestの

setFetchBatchSize 

方法を検討することができます。

2

あなたはBEGINSWITHをやっています - それは非常に速い操作ではありません!しかし、有限の数の言語があるので、エミュムがおそらく助けになるでしょう。

索引付き整数で、述語で使用するlanguage_idフィールドがあります。あなたはまだだけでなく、言語名を格納し、フェッチされたオブジェクトの一部としてそれを返す、それを検索しないでください:)


PSあなたは「-com.appleを追加することによって、SQLのデバッグをオンにすることができます。 CoreData.SQLDebug 1 'を起動時に渡す引数として使用します(スキームでこれを設定します)。あなたの述語で

(詳細はthis questionを参照)

+0

'language BEGINSWITH%@'は600ms(avg)を要しました。 'language ==%@'は350ミリ秒(平均)でした! – Norbert

+1

私はこれらの行に沿って、BEGINSWITHを使用するよりも速くなるような言語> =%@の比較のようなことをしたことも確信しています。私はそれが2010年のWWDCコア・データ・ビデオにあったと言いたい。 –

+0

それでも文字列の等しい場合は、整数の比較に変換するとさらに高速化されます; SQLでの文字列インデックス処理では、文字列内の特定の文字数のみが考慮されますが、整数のインデックス付けは理想的です。 - http://dev.mysql.com/doc/refman/5.0/en/create-index.html – deanWombourne

関連する問題