7

SO 内を検索しましたが、関係を処理するときにコア データの管理対象オブジェクトを削除する際のパフォーマンスを向上させるための提案は見つかりませんでした。

シナリオは非常に単純です。ここに画像の説明を入力

ご覧のとおり、3 つの異なるエンティティがあります。各エンティティは、次のエンティティとカスケードでリンクされています。たとえば、FirstLevelには と呼ばれる関係がありsecondLevelsますSecondLevel。からFirstLevelへのデリート ルールSecondLevelCascadeSecondLevelで、 からへのデリート ルールFirstLevelNullifyです。SecondLevelと の間に同じ規則が適用されThirdLevelます。

グラフ全体を削除したい場合は、次のような方法を実行します。

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"FirstLevel" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSError *error = nil;
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];    

// delete roots object and let Core Data to do the rest...
for (NSManagedObject *managedObject in items) {
    [context deleteObject:managedObject];
}

カスケードルールを利用して、グラフを削除します。これは少数のオブジェクトでは高速に機能しますが、多くのオブジェクトではパフォーマンスが低下します。さらに、このタイプの削除では、ディスクへの往復が多いと思います (よくわかりませんが)。間違っていますか?

したがって、私の質問は次のとおりです。カスケードルールを利用せずにグラフを削除してパフォーマンスを向上させると同時に、グラフの一貫性を維持するにはどうすればよいでしょうか?

前もって感謝します。

編集

モデルに他のエンティティがあるため、ファイル全体を削除できません。

編集2

私が投稿したコードは、サブクラスのmainメソッドにラップされています。NSOperationこのソリューションにより、削除フェーズをバックグラウンドで実行できます。カスケード ルールを利用したため、削除は半自動で実行されます。FirstLevel投稿されたコード内の for ループを使用して、アイテムであるルート オブジェクトのみを削除します。このようにして、Core Data が残りの作業を行ってくれます。私が疑問に思っているのは次のことです:グラフの一貫性を失うことなく、その半自動削除操作をバイパスして手動で行うことは可能ですか?

4

2 に答える 2

5

データベース内のオブジェクトをトラバースして削除するのにかかる時間については、どうすることもできません。ただし、UI がブロックされないように、バックグラウンドで実行できます。

たとえば、(コードはARCを想定しています-そして、タイプされただけです-コンパイルされていません)...

- (void)deleteAllLevelsInMOC:(NSManagedObjectContext*)moc
{
    // Create a context with a private queue, so access happens on a separate thread.
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    // Insert this context into the current context hierarchy
    context.parentContext = context;
    // Execute the block on the queue of the context
    context.performBlock:^{
            NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"FirstLevel"];
            // This will not load any properties - just object id
            fetchRequest.includesPropertyValues = NO;
            // Iterate over all first-level objects, deleting each one
            [[context executeFetchRequest:fetchRequest error:0] 
                enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                [context deleteObject:obj];
            }];
            // Push the changes out of the context
            [context save:0];
    }];
}

RootLevel オブジェクトをデータ モデルに追加し、それを第 1 レベルのオブジェクトに 1 対多の関係にすることができることに注意してください。次に、(ルート オブジェクトが 1 つしかない場合) その 1 つのルート オブジェクトを削除するだけで、CoreData 内の他のすべてが削除されます。多くの FirstLevel オブジェクトがある場合は、それが適しています。

または、「新しい」コンテキストを永続ストアに直接接続し、変更を加えて、他のコンテキストに変更通知を監視させることもできます。

ところで、UIManagedDocument を使用している場合は、この種のバックグラウンドを無料で取得できます。これは、独自のキューで実行されている親コンテキストが既に存在し、メイン コンテキストへのすべての変更が親に渡されて、実際にデータベースの作業を行うためです。

編集

手動で行うこともできますが、カスケード ルールをオフにする必要があります。私は、CoreData にできる限り多くのことをしてもらいたいと考えています。それは私のエラーのマージンを減らします。

バックグラウンド スレッドで既に削除している場合、パフォーマンスの問題はどのように見られますか? その削除中にクエリを実行する必要があります...つまり、すべての作業を行うMOCを使用しています。

UIManagedDocument から教訓を得る必要があります。プライベート キューで実行される MOC が必要です。それはすべての本当の仕事をします。そのワーカー キューに作業を渡すだけの子 MOC があります。

削除するグラフにないオブジェクトを実際にクエリしている場合、永続ストア コーディネーターのシリアル化プロパティによってハングアップする可能性があります。その場合は、別のコーディネーターを検討するか、店舗を 2 つだけにするかを検討する必要があります。

そうすれば、他のオブジェクトの要求に応答しながら、グラフ内のオブジェクトを必要なだけ削除できます。

于 2012-04-19T13:48:18.580 に答える
1

私は通常、ここで説明されているように Core Data SQL トレースをオンにし ます-com.apple.CoreData.SQLDebug 1: http://useyourloaf.com/blog/2010/3/11/debugging-core-data-on-the-iphone.html舞台裏でそれが行われることを期待してください。

[moc save:...] にそれだけの時間がかかり、削除するオブジェクトを取得するための実際の fetchrequest ではないことを確認しましたか? その場合は、それらの最初のレベルのオブジェクトをバッチでフェッチ (および削除) できます。

于 2012-04-20T15:26:34.237 に答える