2013-01-31 6 views
7

Chcę wstawić 40000 rekordów, które otrzymuję z usługi sieci Web do bazy danych sqlite w mojej aplikacji na iPada.Jak szybko wstawić 40000 rekordów do bazy danych sqlite w iPadzie?

Napisałem poniższy kod, ale zajmuje to około 20 minut, czy istnieje szybszy sposób?

- (NSArray *)insertPriceSQLWithPrice:(Price *) price 
{ 

SQLiteManager *dbInfo = [SQLiteManager sharedSQLiteManagerWithDataBaseName:@"codefuel_catalogo.sqlite"]; 


sqlite3 *database; 

NSString *querySQL=[self formatStringQueryInsertWithTable:@"prices_list" andObject:price]; 


if(sqlite3_open([dbInfo.dataBasePath UTF8String], &database) == SQLITE_OK) 
{ 
    sqlite3_stmt * compiledStatement; 


    const char *query_stmt = [querySQL UTF8String]; 

    int result = sqlite3_prepare_v2(database, query_stmt, -1, &compiledStatement, NULL); 

    if (result == SQLITE_OK) 
    { 
     int success = sqlite3_step(compiledStatement); 

     NSLog(@"el numero de success es -> %i",success); 
     if (success == SQLITE_ERROR) 
      NSLog(@"Error al insertar en la base de datps"); 

    } 
    else 
     NSLog(@"Error %@ ERROR!!!!",querySQL); 

    sqlite3_finalize(compiledStatement); 
} 

sqlite3_close(database); 
return nil; 
} 
+8

Podjęłbym otwieranie i zamykanie bazy danych z metody. To kosztuje cię sporo czasu. Stwórz i utrzymuj connectoin przez każde z 40 000 insertów, a następnie zniszcz je po zakończeniu. Ponadto, dzienniki NSLog mogą spowalniać faktyczną realizację. Próbowałem uruchomić jeden bez logów, aby zobaczyć, ile czasu to trwa. – Jeremy1026

+0

Czy otwierasz ponownie bazę danych 40000 razy? (Powinieneś także uniknąć ponownej kompilacji instrukcji raz na rekord, a lepiej zrobić wszystkie wkładki w pojedynczej transakcji - ale to jest mniej ważne niż ponowne otwarcie dla każdego wiersza). –

+2

Możesz wstawić wiele wierszy na insert z właściwym zapytaniem i zawijać cały proces w transakcji - w tej chwili SQLite musi spłukać się na dysk po każdym wstawieniu, który spowolni cię w dół. Możesz także ponownie użyć przygotowanego wyciągu, po prostu ponownie wiążąc zmienione wartości za każdym razem. –

Odpowiedz

22

Są trzy rzeczy, które trzeba zrobić, aby przyspieszyć wstawki:

  • Move wezwanie sqlite3_open poza pętlą. Obecnie pętla nie jest widoczny, więc zakładam, że jest poza fragmencie kodu
  • Dodaj BEGIN TRANSACTION i COMMIT TRANSACTION połączeń - trzeba rozpocząć transakcję przed pętli wkładania i zakończyć go zaraz po pętli jest skończona.
  • Producent formatStringQueryInsertWithTable naprawdę parametryzowane - Obecnie wydaje się, że nie używasz sprawozdań przygotowanych do ich najpełniejszym, bo mimo korzystania sqlite3_prepare_v2 to, nie masz połączenia z sqlite3_bind_XYZ w kodzie.

Oto a nice post that shows you how to do all of the above. Jest to zwykły C, ale będzie działał dobrze jako część programu Celu C.

char* errorMessage; 
sqlite3_exec(mDb, "BEGIN TRANSACTION", NULL, NULL, &errorMessage); 
char buffer[] = "INSERT INTO example VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"; 
sqlite3_stmt* stmt; 
sqlite3_prepare_v2(mDb, buffer, strlen(buffer), &stmt, NULL); 
for (unsigned i = 0; i < mVal; i++) { 
    std::string id = getID(); 
    sqlite3_bind_text(stmt, 1, id.c_str(), id.size(), SQLITE_STATIC); 
    sqlite3_bind_double(stmt, 2, getDouble()); 
    sqlite3_bind_double(stmt, 3, getDouble()); 
    sqlite3_bind_double(stmt, 4, getDouble()); 
    sqlite3_bind_int(stmt, 5, getInt()); 
    sqlite3_bind_int(stmt, 6, getInt()); 
    sqlite3_bind_int(stmt, 7, getInt()); 
    if (sqlite3_step(stmt) != SQLITE_DONE) { 
     printf("Commit Failed!\n"); 
    } 
    sqlite3_reset(stmt); 
} 
sqlite3_exec(mDb, "COMMIT TRANSACTION", NULL, NULL, &errorMessage); 
sqlite3_finalize(stmt); 
5

Dla mnie, nazywając rozpocząć transakcji następnie ładuje jakieś 20 insertów, następnie wywołanie dokonać transakcji dał wzrost wydajności 18x - wielki napiwek! Buforowanie przygotowanych oświadczeń było małą pomocą.

Powiązane problemy