2011-09-01 25 views
7

mi aplicación de iPhone tiene una entidad Words con los atributos word, length y language. Ambos están indexados: Entity and attributesSimple Core Data fetch es muy lento

Copié el modelo de cdata y la base de datos a una aplicación importadora separada donde se prellena con aproximadamente 400k palabras en diferentes idiomas. Verifiqué la importación buscando en el archivo SQLite y luego copié la base de datos precargada al proyecto de iPhone.

Primero pensé que el predicado (simple) es el problema. Pero incluso después de eliminar el predicado de la solicitud de búsqueda, se necesita mucho tiempo para su ejecución:

2011-09-01 09:26:38.945 MyApp[3474:3c07] Start 
2011-09-01 09:26:58.120 MyApp[3474:3c07] End 

Esto es lo que se ve mi código como:

// 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; 

es el número de entradas en la base de datos un problema para Core Data?


EDITAR: Como gcbrueckmann y jrturton señalaron, es un buen punto para establecer fetchBatchSize. Pero el tiempo ha podido recuperar sigue siendo insatisfactoria:

  • 2 segundos con un conjunto de predicados:

    NSPredicate * predicado = [NSPredicate predicateWithFormat: @ "== longitud% d e Idioma BEGINSWITH% @", longitud de palabra, lng ]; [fetchRequest setPredicate: predicate];

  • 7 segundos con el conjunto de tamaño de lote:

    [fetchRequest setFetchBatchSize: 1];

  • 1 segundo con un tanto el predicado y el tamaño del lote establecido

¿Existe todavía otro cuello de botella?

+0

en su predicado es el lenguaje, posiblemente, más restrictiva que la longitud, a veces el orden de los controles subyacentes pueden acelerar las cosas así. por ejemplo, en este caso, si el 60% de las palabras cumplieron con los criterios de su longitud, pero solo el 40% cumplía con los criterios de idioma, sería mejor que primero se hiciera la verificación del idioma. La otra cosa podría ser si necesita esto más rápido sería tenerlo precargado y luego filtrar una matriz en la memoria no estoy seguro si su aplicación de iPhone puede manejar eso sin embargo. –

+0

En este caso, la primera consulta compara números enteros (la indexación lo hará muy rápido) y la segunda es una comparación de cadenas (incluso una cadena indexada no va a ser rápida) - Me sorprendería si ayudara a reordenar la consulta. Sin embargo, pruébalo, ¡me interesaría ver si me ayudó! – deanWombourne

+0

Ah, se me olvidó mencionarlo: ya he intentado cambiar el orden del predicado, no acelera la búsqueda. – Norbert

Respuesta

11

Dado que no está limitando el conjunto de resultados de ninguna manera ir a buscar 400,000 objetos a la vez definitivamente será una carga en los datos centrales. Hay varias maneras de mejorar el rendimiento:

Al cambiar la solicitud de búsqueda fetchBatchSize se limita el número de objetos que la recuperación guardará en la memoria a la vez. Esta característica es completamente transparente para su aplicación, por lo que definitivamente vale la pena intentarlo.

Si no necesita objetos totalmente desarrollados, puede considerar cambiar la solicitud de búsqueda resultType a un valor más apropiado. Especialmente si solo está interesado en algunos de los valores de un objeto, es buena idea usar NSDictionaryResultType.

Por último, las propiedades fetchLimit y fetchOffset le permiten limitar el rango de resultados, si desea administrar el procesamiento por lotes usted mismo. Esta es una buena idea si el manejo de cada uno de los objetos resultantes utiliza mucha memoria porque puede envolver cada lote en un NSAutoreleasePool (simplemente no se sienta tentado a crear un grupo de autorrelease para cada objeto de resultado).

Supongo que 1 seg. podría ser tan rápido como sea posible en su caso, incluso si recurre a una base de datos simple de Sqlite. La única optimización adicional que puedo pensar es usar una tabla por idioma (en lugar de poner palabras de todos los idiomas en una sola tabla). Esto, por supuesto, solo funcionará con Sqlite a menos que defina entidades separadas para todos los idiomas, i. mi. tome su entidad Words como está y hágala abstracta. A continuación, agregue subentidades como EnglishWord, etc. Los objetos de diferentes entidades se almacenan en tablas separadas. Por lo tanto, combinado con los parámetros fetchBatchSize y predicate, esto debería funcionar de forma similar al enfoque Sqlite con tablas separadas para todos los idiomas.

+0

'fetchBatchSize' es definitivamente un buen punto. Pero desafortunadamente todavía demora 2 segundos para escribir una palabra. – Norbert

+0

¿Está utilizando una base de datos Sqlite básica una opción en su caso? Parece que los objetos existentes no se modifican, por lo que Core Data probablemente no tendrá (m) ninguna ventaja sobre Sqlite. 400,000 realmente es un gran conjunto de datos en el iPhone. ¿Sería una opción tener una tabla por idioma? – gcbrueckmann

+0

Sí, ya pensé en volver a SQLite simple, pero pensé que todavía podría haber un cuello de botella que no veo. – Norbert

1

Eso recuperaría su base de datos completa de 400k en la memoria que parece mucho. Se podría investigar método

setFetchBatchSize 

de NSFetchRequest que se detiene el marco de regresar objetos completos para todo en su solicitud de búsqueda, en el supuesto de que no es necesario cada objeto vuelto a ser traída desde la tienda en primera instancia.

2

Estás haciendo BEGINSWITH - ¡esa no es una operación muy rápida! Sin embargo, hay un número finito de idiomas, por lo que un emum probablemente lo ayude.

Tiene un campo language_id que es un entero indexado y lo usa en su predicado. Todavía se puede almacenar el nombre del idioma, así y devolverlo como parte del objeto exagerado, simplemente no buscar en él :)


PS Puede activar la depuración de SQL mediante la adición de '-com.apple. CoreData.SQLDebug 1 'como un argumento pasado en el lanzamiento (configúrelo en su Esquema) - esto podría ayudarlo a ver qué SQL está haciendo detrás de las escenas.

(ver this question para más detalles)

+0

'language BEGINSWITH% @' tomó 600ms (avg); 'language ==% @' tomó 350ms (avg)! – Norbert

+1

Creo que a lo largo de estas líneas también he visto decir que hacer cosas como una comparación de idioma> =% @ es más rápido que usar BEGINSWITH. Quiero decir que fue en los videos de datos centrales de la WWDC 2010. –

+0

Si eso es igualdad de cadenas, obtendrá aún más aceleración si realiza una conversión para comparar enteros;) La indexación de cadenas en SQL solo considera una cierta cantidad de caracteres en la cadena, ¡mientras que indexar un entero es ideal! - http://dev.mysql.com/doc/refman/5.0/en/create-index.html – deanWombourne