Rendimiento de CloudKit utilizando una CKReference vs. CKRecord

Digamos que tengo un CKRecord de recordType Post. Publique algunos valores, como título y descripción. Cuando se muestra un post en la aplicación, se acompaña del nombre y la image de perfil del usuario que lo escribió (llamémosles el escritor). Mi pregunta es: ¿sería mejor almacenar una CKReference en el Perfil del Escritor (el Perfil es otro tipo de logging que contiene los detalles del Escritor), o sería mejor agregar directamente los detalles del Escritor al Post cuando lo escriben?

La primera opción tiene mucho sentido desde la perspectiva de un esquema de database, pero parece realmente malo desde el punto de vista del performance. Con miles de usuarios en este sistema, la cantidad de capturas y el time para cargarlos todo parece irrazonable.

La primera parte implica cargar todas las publicaciones.

 func loadPosts() { // ...Setup the query publicData.performQuery(query, inZoneWithID: nil) { (results: [CKRecord]?, error: NSError?) in if let posts = results { self.loadProfiles(posts) } } } 

Una consulta realizada, ahora llamamos loadProfiles

 func loadProfiles(posts: [CKRecord]) { // Get the reference IDs out of the Posts var referenceIDs = [CKRecordID]() for post in posts { // Get the reference from the post // Append the recordID to the referenceIDs array } // Perform the Profiles fetch let fetchOperation = CKFetchRecordsOperation(recordIDs: referenceIDs) fetchOperation.fetchRecordsCompletionBlock = { records, error in // ...Handle the fetched Profiles // Everything has been fetched, update the UI now dispatch_async(dispatch_get_main_queue(), { self.tableView.reloadData() }) } CKContainer.defaultContainer().publicCloudDatabase.addOperation(fetchOperation) } 

En esa function, pasamos time agarrando los ID de reference. Luego pasamos time haciendo la búsqueda del perfil. ¡Ten en count que todo esto está sucediendo después de la búsqueda original de Post!

… Yikes. Incluso con algún tipo de sistema de caching, la búsqueda original sería una locura (especialmente con muchos usuarios).

Entonces, ¿sería mejor agregar directamente los detalles del Escritor al Post cuando lo escriben? Pros de esto: less búsquedas, carga más rápida. Contras de esto: si el escritor cambia sus detalles del perfil, la aplicación deberá recorrer todas sus publicaciones y actualizar manualmente los detalles.

Todo este dilema apesta a elegir su escenario de veneno. ¿Hay una mejor manera de hacer esto?

El término para el intercambio que estás describiendo es desnormalización . Es el dilema que describes. Sopesar los compromisos depende tanto de la tecnología subyacente como del dominio de la aplicación y el comportamiento esperado.

Has descrito dos objects de model, un Post y un Perfil, con una reference de Writer a un Perfil en un Post. No ha descrito exactamente cómo se utilizan, pero voy a asumir como desplazamiento de la list de publicaciones, en una vista de tabla, con el nombre del escritor y la image de perfil en cada celda de la list. Es obvio por qué te preocupa tirar references para cada uno.

La prioridad de CloudKit es minimizar el número de viajes de ida y vuelta al server. Sin embargo, una búsqueda para publicaciones y una segunda búsqueda para los nombres de perfil vinculados no es particularmente onerosa. Muy importante: use la propiedad desinetworkingKeys en búsquedas y consultas aquí y siempre que pueda. CloudKit obtiene el logging completo por defecto, y probablemente pasaría información extraña por cable: es la diferencia entre get los nombres de los usuarios y get los perfiles completos de los usuarios.

El punto para usar desinetworkingKeys siempre que sea posible no se ve afectado en la documentation por su importancia para la optimization y la simplicidad para implementar.

Pero si le preocupa ser receptivo al tirar publicaciones, por ejemplo, si el usuario va a estar esperando mientras tira más, es posible que desee desnormalizar.

También voy a asumir que un perfil no cambia muy a menudo, este es un punto key importante, pero puede cambiar y la aplicación debe tener en count eso. En realidad, es bastante simple: Hacer un seguimiento de las publicaciones para actualizarlas no es ideal, pero no es tan importante, porque es algo único que no esperas que suceda muy a menudo. Debería poder hacerlo con un par de CKQueryOperation / CKModifyRecordsOperation.

De nuevo, asegúrese de usar desinetworkingKeys , especialmente si solo está buscando para actualizar los campos desnormalizados en cada publicación y no planea mostrar ninguno de ellos, no desea pasar el contenido completo de cada publicación a través del cable.

Tenga en count que si desnormaliza con imágenes de perfil, probablemente querrá asegurarse de que está usando el mismo CKAsset, por lo que se genera en el caching y no envía accidentalmente la misma image hacia arriba y hacia abajo y se almacena varias veces. Vea advertencias sobre cómo funciona CKAsset y el almacenamiento en caching local; aparentemente si quieres que se guarden almacenados localmente, tienes que savelo tú mismo.

Y ese es un buen punto para tener en count que todos estos types de datos de CloudKit no se utilizan específicamente como objects de model en su aplicación, y cómo esto interactuará con esa capa afectará las decisiones que tome.

CloudKit es realmente genial, pero en mi opinión se ve frenado por su documentation no sistemática. Tuve la suerte de ir a WWDC este año ('16) y pude hablar con algunos ingenieros de CloudKit, de donde proviene parte de esta información. Espero que esto ayude.