2012-06-19 14 views
7

Estoy frente a un problema durante el uso de SQLite en iOS 5. Soy registros de ir a buscar a partir de dos tablas: una en otra receta & en los ingredientes de un Menu.dbproblema de rendimiento en iOS 5 para SQLite

De Tabla de recetas Obtengo todo el registro y uno recipeid sobre esa base, obtengo registros de la tabla de ingredientes. No se necesita tiempo para recuperar el registro cuando se ejecuta en iOS 4.2, pero cuando ejecuto en iOS 5, lleva tiempo recuperar los registros. Ver el siguiente código:

NSString *query = [NSString stringWithFormat:@"select id from Recipes"]; 
sqlite3_stmt *selectstmt; 
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) { 
    while(sqlite3_step(selectstmt) == SQLITE_ROW) { 
     rcp.recipeID = sqlite3_column_int(selectstmt, 0); 
     NSString *sql = [NSString stringWithFormat:@"select Name from Ingredients where recipeId = %d",rcp.recipeID]; 
     sqlite3_stmt *stmt2; 
     if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt2, NULL) == SQLITE_OK) { 
      while(sqlite3_step(stmt2) == SQLITE_ROW) {} 
     } 
    } 
} 

¿Por qué es este problema viene en iOS 5.0, el mismo código se ejecuta correctamente en iOS 4.0, 4.2?

Lo sé, el código que he escrito es el correcto, quiero saber la razón exacta detrás de este problema de rendimiento en iOS 5.0 para Sqlite bcoz mi aplicación está totalmente construida alrededor de la base de datos.

+0

En el proyecto se crean archivos 2 .sql o no –

+0

Sospecho que hay una diferencia en la base de datos. (¿Ha verificado que obtiene los mismos resultados en ambos casos?) –

+0

Tengo un Menu.db y en eso tengo dos tablas. – Rupesh

Respuesta

1

Pruebe con el uso de dos funciones diferentes Después de terminar con la ejecución completa de su primera consulta, comience con la segunda consulta.

Por ejemplo: -

NSString *query = [NSString stringWithFormat:@"select id from Recipes"]; 
sqlite3_stmt *selectstmt; 
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) { 
    while(sqlite3_step(selectstmt) == SQLITE_ROW) { 
     rcp.recipeID = sqlite3_column_int(selectstmt, 0); 
    } 
} 

y luego llamar

NSString *sql = [NSString stringWithFormat:@"select Name from Ingredients where recipeId = %d",rcp.recipeID]; 
      sqlite3_stmt *stmt2; 
      if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt2, NULL) == SQLITE_OK) { 
       while(sqlite3_step(stmt2) == SQLITE_ROW) {} 

Espero que esto ayude a resolver su problema.

1

Creo que vinculó contra libsqlite3.dylib. En su lugar, debe vincular la biblioteca libsqlite3.0.dylib.

+0

He usado libsqlite3.0.dylib. – Rupesh

1

Si desea contever su .db a .sqlite

abrir el archivo .db seleccione la tabla Archivo-> Exportar -> Tabla de CSV (guardar el archivo con formato .csv) (como este camino selecciona toda la tabla) continuación, abra el archivo .sqlite Archivo-> Importar -> tabla de CSV después de su archivo .csv elegir un cuadro de diálogo aparece en que los nombres de campo Extracto de primera línea debe marcar marcado ahora su archivo de SQLite está listo.

poner este archivo en su proyecto

a continuación, establecer su .sqlite/ruta de archivo .db

, ahora vuestros consulta de selección que como esto

#import <sqlite3.h> 


    -(void)SelectSqlData:(NSString *)SearchString 
    { 
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
     NSString *documentsDirectory = [paths objectAtIndex:0]; 
     NSString *path = [documentsDirectory stringByAppendingPathComponent:@"yourfileName.sqlite"]; 
     sqlite3_stmt *compiledStatement; 
     sqlite3 *database; 
     if(sqlite3_open([path UTF8String], &database) == SQLITE_OK) { 

      const char *sqlStatement; 

      sqlStatement = "select c.field1,c.field2,c.field3,c.field4 from YourTableName1 as c, YourTableName2 as b where b.Artist_Id = ?"; 

      sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL); 

      //printf("\nError===%s",sqlite3_errmsg(database)); 


      if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) { 

       sqlite3_bind_text(compiledStatement,1,[SearchString UTF8String] , -1,SQLITE_STATIC); 

       while(sqlite3_step(compiledStatement) == SQLITE_ROW) 

       { 

         NSString *str_field1=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)]; 

         NSString *str_field2=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)]; 

         NSString *str_field3=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)]; 

         NSString *str_field4=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)]; 


    // add str_field into array 


      } 

      } 

      sqlite3_finalize(compiledStatement); 


     } 


     sqlite3_close(database); 
    } 
1

Esto probablemente no es la respuesta lo que está buscando, pero aquí hay un pequeño consejo para mejorar el rendimiento.

NSString *query = [NSString stringWithFormat:@"select id from Recipes"]; 
sqlite3_stmt *selectstmt; 

if(sqlite3_prepare_v2(database, [query UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) { 
    while(sqlite3_step(selectstmt) == SQLITE_ROW) { 
     rcp.recipeID = sqlite3_column_int(selectstmt, 0); 

     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     //NSString *sql = [NSString stringWithFormat:@"select Name from Ingredients where recipeId = %d",rcp.recipeID];// 
     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

     sqlite3_stmt *stmt2; 
     if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt2, NULL) == SQLITE_OK) { 
      while(sqlite3_step(stmt2) == SQLITE_ROW) {} 
     } 
    } 
} 

Cada iteración del bucle while, se crea un nuevo objeto NSString (NSString *sql = ...), así que tal vez su lugar debe hacer esto:

NSString *query = [NSString stringWithFormat:@"select id from Recipes"]; 
NSString *sql = [NSString stringWithFormat:@"select Name from Ingredients where recipeId = %d",rcp.recipeID]; 
sqlite3_stmt *selectstmt; 

if(sqlite3_prepare_v2(database, [query UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) { 
    while(sqlite3_step(selectstmt) == SQLITE_ROW) { 
     rcp.recipeID = sqlite3_column_int(selectstmt, 0); 
     sqlite3_stmt *stmt2; 
     if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt2, NULL) == SQLITE_OK) { 
      while(sqlite3_step(stmt2) == SQLITE_ROW) {} 
     } 
    } 
} 

Espero que esto ayude un poco!

1

La función GetListBySQL está optimizada y las versiones de iOS son independientes. Puede que te ayude.

-(NSMutableArray*)GetListBySQL:(NSString*)SQL 
{ 
NSMutableArray* Array; 

Array=[[NSMutableArray alloc]init]; 
NSStringEncoding enc = [NSString defaultCStringEncoding]; 

sqlite3_stmt *select_statement=nil; 

if (sqlite3_prepare_v2(database, [SQL UTF8String], -1, &select_statement, NULL) != SQLITE_OK) { 
    NSString *errString = [NSString stringWithFormat:@"%@", [@"Fail" stringByReplacingOccurrencesOfString:@"#" withString:[NSString stringWithCString:sqlite3_errmsg(database) encoding:enc] ]]; 
    NSAssert1(0, @"%@", errString); 
} 

int columncount=sqlite3_column_count(select_statement); 

NSMutableDictionary* dic; 

while (sqlite3_step(select_statement) == SQLITE_ROW) 
{ 
    dic=[[NSMutableDictionary alloc]init]; 

    for(int j=0;j<columncount;j++) 
    { 
     if(sqlite3_column_text(select_statement, j)!=nil) 
      [dic setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(select_statement, j)] forKey:[NSString stringWithUTF8String:(char *)sqlite3_column_name(select_statement,j)]]; 
     else 
      [dic setObject:@"" forKey:[NSString stringWithUTF8String:(char *)sqlite3_column_name(select_statement,j)]]; 
    } 

    [Array addObject:dic]; 
    [dic release];  
} 

sqlite3_finalize(select_statement); 

NSMutableArray *arr = [[NSMutableArray alloc] initWithArray: Array]; 

[Array release]; 

return arr; 
} 
0

Otra alternativa es cambiar SQLite a una base de datos Key/Value como LevelDB (de google) o TokyoCabinet. Estoy usando LevelDB para dos proyectos en este momento y está funcionando realmente bien, y también usé TokyoCabinet en el pasado, el problema con TokyoCabinet es que es LGPL, así que no estoy seguro si es totalmente compatible con el entorno iOS, pero De todos modos, tenía varias aplicaciones en la tienda de aplicaciones usando el gabinete de Tokio (no se lo digas a Apple).

Para usar ambos necesitará una envoltura (o tal vez usted puede desarrollar la suya propia). Se trata de una comparación rápida y las envolturas disponibles:

  • LevelDB: Parece ser uno de los más rápidos por ahí (si no el más rápido, echar un vistazo a su benchmarks). Y como envoltorio actualmente estoy usando NULevelDB, si tiene algún problema al agregarlo a su proyecto, hágamelo saber (tuve algunos).

  • TokyoCabinet: Se parece que no hay tan rápido como LevelDB (no he ejecutar las pruebas, se me cayó a causa de los problemas de licencia), pero en la página oficial que recomiendan el uso de su nueva biblioteca llamada KyotoCabinet que no he 't probado todavía, pero se supone que es más rápido. La envoltura que utilicé fue hecha por el increíble Aaron Hillegass, y se llama BNRPersistence.

Como recomendación, darle una oportunidad a LevelDB, hay una comunidad grande detrás, y la envoltura (NULevelDB) es simple y agradable.

¡Buena suerte!