2013-01-31 11 views
7

Webサービスから取得した40000のレコードをiPadアプリのsqliteデータベースに挿入します。iPadのsqliteデータベースに40000レコードを高速に挿入する方法

私は次のコードを書いていますが、それは約20分かかります、より速い方法はありますか?

- (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

私はメソッドの外にデータベースのオープンとクローズを行います。それはあなたにかなりの時間をかけています。 40,000のインサートのそれぞれを通してconnectoinを作成して永続させ、それが完了すると破棄します。また、NSLogが実際の実行を遅くしている可能性があります。私はどれくらいの時間がかかるかを見るためにログを使わずに1つを実行しようとします。 – Jeremy1026

+0

データベースを40000回再オープンしますか? (レコードごとにステートメントを再コンパイルしないでください。すべての挿入を1回のトランザクションで行う方が良いですが、各行の再オープンよりも重要です。 –

+2

右のクエリでインサートごとに複数の行を挿入し、プロセス全体をトランザクションにラップすることができます。挿入が終わるたびにSQLiteがディスクにフラッシュする必要があります。また、準備された文を再利用するだけで、毎回変更された値を再バインドすることができます。 –

答えて

22

あなたが挿入を高速化するために行う必要がある三つのことがあります。

  • は、ループの外sqlite3_openの呼び出しを移動しは現在、ループが示されていないので、私はそれがBEGIN TRANSACTIONCOMMIT TRANSACTION通話の追加コードスニペットの外
  • であると仮定 - あなたが挿入ループ前にトランザクションを開始し、ループが終わった直後、それを終了する必要があります。
  • formatStringQueryInsertWithTable真のパラメータ化を作る - sqlite3_prepare_v2を使用しているにもかかわらず、あなたのコード内sqlite3_bind_XYZのない電話を持っていないため、現在あなたが彼らの最大限にプリペアドステートメントを使用していないことが表示されます。

ここはa nice post that shows you how to do all of the aboveです。これは普通のCですが、Objective Cプログラムの一部として正常に動作します。その後、トランザクションをコミット呼び出し、その後、いくつかの20のインサートをロードするBEGIN TRANSACTIONを呼び出す

私にとって
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

は、18倍の性能向上を与えた - 大きなヒントを!準備されたステートメントをキャッシュすることはほとんど役に立たなかった。

関連する問題