Performance Core Data en suppression avec delete des relations en cascade

Bonjour,



Je suis en train de tester mon appli iOS sur les gros volumes et particulièrement les suppressions massive d'objets Core Data. L'astuce que je propose fonctionne également sur des volumes raisonnables.



J'ai trouvé une astuce pour améliorer les performances de ce type de traitement et particulièrement lorsque les objets en question ont des relations avec d'autres objets avec la règle Delete Rule : Cascade.



Si vous connaissez déjà  cette astuce... tant mieux :-) Dans le doute, je publie :-)



Ce que j'ai constaté en premier lieu c'est que lorsque je delete un objet Core Data qui possède des relations avec la règle de delete en cascade, il y a systématiquement une levée du fault sur les relations en question.



Si, par exemple, j'ai un objet MenuRestaurant qui fait référence à  des Plats lesquels font références à  des instructions de préparations de telle sorte que mon graphe s'exprime ainsi :



MenuRestaurant <->>Plats<->>Préparations.



Avec l'utilisation des règles de delete en cascade, la suppression d'un MenuRestaurant va automatiquement entrainer la suppression des Plats et des Préparations. C'est plutôt pratique.



Le problème est que Core Data va lever le fault pour chaque Plats et Préparations liés à  l'objet MenuRestaurant qui est supprimé. Ce qui peut coûter cher en temps de traitement. Faut-il souligner également que la levée du fault se fait même si la relation est vide.



On peut facilement vérifier ce principe en utilisant l'argument -com.apple.CoreData.SQLDebug 1 au lancement de l'appli et qui va loguer toutes les actions que Core Data réalise en cachette.



Comment faire pour que Core Data n'ai plus besoin de lever les faults lors du delete ?



En réalisant avant l'instruction du delete, un fetch sur les plats du menu à  supprimer. Du genre :


<br />
		NSFetchRequest *reqPlat = [NSFetchRequest fetchRequestWithEntityName:@&quot;Plat&quot;];<br />
		NSPredicate *predPlats = [NSPredicate predicateWithFormat:@&quot;menu == %@&quot;, self.menu.objectID];<br />
		[reqPlat setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:@&quot;preparations&quot;, @&quot;AutresRelationsSiNecessaire...&quot;, nil]];<br />
		[reqPlat setPredicate:predPlats];<br />
		NSArray *cascadedPlatsToBeDeleted = [self.managedObjectContext executeFetchRequest:reqPlat error:&amp;error];<br />
		if (cascadedPlatsToBeDeleted == nil) {<br />
			NSLog(@&quot;Error while fetching Plat for cascade deletion : %@, %@&quot;, error, [error userInfo]);<br />
			abort();<br />
		}<br />




Avec un fetch de ce type - notez l'importance du setRelationshipKeyPathsForPrefetching: - j'ai constaté que toutes les levées de fault disparaissaient de la log Core Data (logique en fait). L'important est qu'ici on récupère tous les objets en une seule étape (plutôt que de laisser core data le faire lui même un objet après l'autre).



Pour information, sur des milliers d'objet à  supprimer, je suis passé d'un temps de traitement de 11 secondes à  6 secondes. C'est toujours ça de gagné.

Sur environ 500 objets à  supprimer je gagne environ 3 secondes.

Sur moins de 500 objets je gagne 1 seconde.

Tests réalisés sur iDevice.
Mots clés:

Réponses

  • Tres tres intéressant ca.



    J'avais vu quelques tutos sur le net avec ca mais pas aussi bien expliqué.



    j'utilise bientôt image/smile.png' class='bbc_emoticon' alt=':)' />



    Merci du partage image/smile.png' class='bbc_emoticon' alt=':)' />





    Autre question sur les suppression en cascade est t'il possible de vérifier qu'on aille bien assez loin dans les relation et qu'on libère bien tout l'espace?

    Merci de l'info.
  • Je ne connaissais pas l'astuce est c'est pas con du tout en effet !
  • 'yoann' a écrit:


    Je ne connaissais pas l'astuce est c'est pas con du tout en effet !




    J'en découvre tous les jours avec ce core data... là  suis en train de mettre au point un pattern permettant la mise à  jour simultanée (en background et via l'interface utilisateur) d'un même objet en utilisant les nested context. (Parce que dans mon appli j'ai encore des erreurs de faults qui trainent et dont je n'arrive pas à  me débarrasser avec mon implémentation initiale).
  • 'Kubernan' a écrit:


    J'en découvre tous les jours avec ce core data... là  suis en train de mettre au point un pattern permettant la mise à  jour simultanée (en background et via l'interface utilisateur) d'un même objet en utilisant les nested context. (Parce que dans mon appli j'ai encore des erreurs de faults qui trainent et dont je n'arrive pas à  me débarrasser avec mon implémentation initiale).




    Je suis intéresser par le résultat si tu peux le partager.
  • 'yoann' a écrit:


    Je suis intéresser par le résultat si tu peux le partager.




    J'y penserai :-) Là  suis encore en phase de conception et tests...
Connectez-vous ou Inscrivez-vous pour répondre.