デイブ・デロングはすべてについてちょうど、まあ、専門家であり、私は水の上を歩く方法をイエスに言っているようなので、私は感じています。確かに、彼の投稿は2009年からのもので、これは長い時間前です。
しかし、Botによって投稿されたリンクのアプローチは、必ずしも大きな削除を処理する最良の方法ではありません。
基本的に、この投稿は、オブジェクトIDをフェッチし、各オブジェクトでdeleteを呼び出すことを提案しています。
問題は、1つのオブジェクトを削除すると、関連するすべての関係を処理する必要があり、それがさらにフェッチを引き起こす可能性があるということです。
このように大規模な削除を行う必要がある場合は、特定のコアデータストアのテーブルを分離できるように全体のデータベースを調整することをお勧めします。そうすれば、ストア全体を削除し、残したい小さなビットを再構築することができます。おそらく最も速いアプローチだろう。あなたがオブジェクト自体を削除する場合
しかし、あなたはこのパターンに従ってください...
は、自動解放プール内で、バッチであなたの削除を行い、そして任意のカスケード接続関係をプリフェッチしてください。これらはすべて、実際にデータベースにアクセスしなければならない回数が最小限に抑えられ、削除の実行に要する時間が短縮されます。ダウンに来て提案のアプローチでは、
...
- がリストを
- 反復を削除するすべてのオブジェクトのたObjectIdを取得し、あなたの場合は、各オブジェクトに
を削除カスケード関係を持っていると、データベースへの余分なトリップが発生し、IOは非常に遅いです。データベースにアクセスする回数を最小限に抑えたいとします。
最初は不自然なように聞こえるかもしれませんが、削除したいと考えるよりも多くのデータを取り込む必要があります。その理由は、いくつかのIO操作ですべてのデータをデータベースからフェッチできるからです。
だから、あなたのフェッチ要求に、設定したい...それらの関係は、カスケードルールを削除した可能性のあるすべての関係を表す
[fetchRequest setRelationshipKeyPathsForPrefetching:@[@"relationship1", @"relationship2", .... , @"relationship3"]];
。
フェッチが完了すると、削除されるすべてのオブジェクトと、削除されるオブジェクトの結果として削除されるオブジェクトがあります。
階層が複雑な場合は、できるだけ先にプリフェッチする必要があります。それ以外の場合は、オブジェクトを削除すると、Core Dataはカスケード削除を管理できるように、オブジェクトごとに個々の関係を個別にフェッチする必要があります。
これにより、結果としてより多くのIO操作が行われるため、時間がかかります。
フェッチが完了したら、オブジェクトをループして削除します。大規模な削除の場合、大規模な処理のスピードアップを見ることができます。
さらに、オブジェクトがたくさんある場合は、複数のバッチに分割し、自動解放プール内で実行します。
最後に、別のバックグラウンドスレッドでこれを行います。これにより、UIは保留されません。永続的なストアコーディネータに接続された別個のMOCを使用して、主MOCにDidSave通知を処理させて、そのコンテキストからオブジェクトを削除させることができます。これはコードのように見えますが、擬似コードとして扱い
...もちろん
NSManagedObjectContext *deleteContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateConcurrencyType];
// Get a new PSC for the same store
deleteContext.persistentStoreCoordinator = getInstanceOfPersistentStoreCoordinator();
// Each call to performBlock executes in its own autoreleasepool, so we don't
// need to explicitly use one if each chunk is done in a separate performBlock
__block void (^block)(void) = ^{
NSFetchRequest *fetchRequest = //
// Only fetch the number of objects to delete this iteration
fetchRequest.fetchLimit = NUM_ENTITIES_TO_DELETE_AT_ONCE;
// Prefetch all the relationships
fetchRequest.relationshipKeyPathsForPrefetching = prefetchRelationships;
// Don't need all the properties
fetchRequest.includesPropertyValues = NO;
NSArray *results = [deleteContext executeFetchRequest:fetchRequest error:&error];
if (results.count == 0) {
// Didn't get any objects for this fetch
if (nil == results) {
// Handle error
}
return;
}
for (MyEntity *entity in results) {
[deleteContext deleteObject:entity];
}
[deleteContext save:&error];
[deleteContext reset];
// Keep deleting objects until they are all gone
[deleteContext performBlock:block];
};
[deleteContext preformBlock:block];
は、あなたが適切なエラー処理を行う必要があるが、それは基本的な考え方です。
削除するデータがあまりにも多い場合は、バッチでフェッチしてください。これにより、メモリが不自由になることがあります。 すべてのプロパティを取得しないでください。 IO操作を最小限に抑えるために関係をプリフェッチします。 メモリを増やさないようにするには、autoreleasepoolを使用してください。 コンテキストを削除します。 タスクをバックグラウンドスレッドで実行します。
本当に複雑なグラフがある場合は、オブジェクトグラフ全体のすべてのエンティティのカスケード関係をすべてプリフェッチしてください。
注意してください。メインコンテキストでは、DeleteSave通知を処理して、削除に合わせてコンテキストを保持する必要があります。
EDIT
感謝。たくさんの良い点。なぜなら、なぜ 別のMOCを作成するのですか?任意のテーブルからすべての行を削除するsqliteを使用して データベース全体を削除しない任意の考えですか? - David
長い削除操作が行われている間はUIがブロックされないように、別のMOCを使用します。データベースへの実際のコミットが発生すると、データベースにアクセスできるスレッドは1つだけなので、他のアクセス(フェッチなど)によって更新が遅れることに注意してください。これは、大きな削除操作をチャンクに分割する別の理由です。小さな作品は、操作全体が完了するまで待つことなく、他のMOCが店にアクセスする機会を提供します。
これが原因で問題が発生した場合は、dispatch_set_target_queue
を介して優先キューを実装することもできますが、これはこの質問の範囲を超えています。
コアデータデータベースでsqliteコマンドを使用する場合、Appleは繰り返しこれは悪い考えであり、Core Dataデータベースファイルに対して直接SQLコマンドを実行しないでください。
最後に、これに注意してください。私の経験では、重大なパフォーマンス上の問題が発生した場合、通常は設計が不良であるか、実装が不適切であることが判明しています。問題をもう一度見直し、このユースケースに合わせてシステムをいくらか再設計できるかどうかを確認してください。
すべてのデータを送信する必要がある場合は、バックグラウンドスレッドでデータベースを照会し、新しいデータをフィルタリングして、データを3つのセットに分割する必要があります。変更が必要なオブジェクト、削除が必要なオブジェクト、挿入される。
このようにして、変更が必要なデータベースのみを変更します。
毎回ほとんど新しいデータがある場合は、これらのエンティティが独自のデータベースを持つデータベースを再構築することを検討してください(データベースにはすでに複数のエンティティが含まれていることが前提です)。そうすれば、ファイルを削除して新しいデータベースでやり直すことができます。それは速いです。今、数千のオブジェクトを再挿入するのは速くないでしょう。
店舗を問わず、手動で関係を管理する必要があります。それは難しいことではありませんが、同じ店舗内の関係のように自動ではありません。
これを実行した場合は、まず新しいデータベースを作成し、既存のデータベースを破棄して新しいデータベースと置き換え、古いデータベースを削除します。
このバッチメカニズムを使用してデータベースを操作するだけで、オブジェクトグラフの管理が不要な場合は、コアデータの代わりにsqliteを使用することを検討してください。
代わりに、通信プロトコルの動作方法を変更することもできます。あなたの顧客リストへの変更をあなたのデバイスに送るだけを検討してください。詳細については、http://stackoverflow.com/questions/5035132/how-to-sync-iphone-core-data-with-web-server-and-then-push-to-other-devices/5052208#5052208を参照してください。どのようにこれを行うことができます。 – chris
http://stackoverflow.com/a/5733105/2412290このサイトは良いアイデアです、使用関係上位エンティティを削除サブ – mosn