2014-11-17 121 views
0

我有下面的代碼可以在Sqlite數據庫中插入數據,但它太慢了。 Sqlite FAQ說它一次可以支持50K的插入。我附上了以下代碼。Sqlite C++插入很慢

SqliteBuffer.h

#ifndef SQLITE_BUFFER_H 
#define SQLITE_BUFFER_H 
#include "sqlite3.h" 
#include <iostream> 
class SqliteBuffer 
{ 
    std::string db_name_; 
    sqlite3 *db_; 
    sqlite3_stmt *insert_stmt_; 
    bool has_transaction_begun; 
public: 
    SqliteBuffer(std::string db_name); 
    ~SqliteBuffer(); 
    int CreateTable(); 
    void SaveMessage(std::string msg); 
    void BeginTransaction(); 
    void EndTransaction(); 
}; 
#endif 

SqliteBuffer.cc

#include "SqliteBuffer.h" 

int SqliteBuffer::CreateTable() 
{ 
    sqlite3_stmt *create = NULL; 
    if(sqlite3_prepare_v2(db_,"CREATE TABLE mytable (sif INTEGER PRIMARY KEY, log VARCHAR);",-1,&create,NULL)==SQLITE_OK){ 
     sqlite3_step(create); 
     sqlite3_finalize(create); 
    } 
    return 0; 
} 
SqliteBuffer::SqliteBuffer(std::string db_name) 
{ 
    int rc = sqlite3_open_v2(db_name.c_str(), &db_, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, NULL); 
    if(rc!=SQLITE_OK){ 
     sqlite3_close_v2(db_); 
    } 
    CreateTable(); 
    rc = sqlite3_prepare_v2(db_, "INSERT INTO mytable(log) VALUES (@LOG)", -1, &insert_stmt_, NULL); 
} 
void SqliteBuffer::SaveMessage(std::string message) 
{ 
    BeginTransaction(); 
    sqlite3_bind_text(insert_stmt_,1,message.c_str(),-1,SQLITE_TRANSIENT); 
    sqlite3_step(insert_stmt_); 
    sqlite3_clear_bindings(insert_stmt_); 
    sqlite3_reset(insert_stmt_); 
} 
void SqliteBuffer::BeginTransaction() 
{ 
    if(has_transaction_begun == false){ 
     has_transaction_begun = true; 
     sqlite3_exec(db_, "BEGIN TRANSACTION;",NULL,NULL,NULL); 
    } 
} 
void SqliteBuffer::EndTransaction() 
{ 
    if(has_transaction_begun == true){ 
     has_transaction_begun = false; 
     sqlite3_exec(db_, "END TRANSACTION;",NULL,NULL,NULL); 
    } 
} 

main.cc

#include "SqliteBuffer.h" 

int main() 
{ 
    SqliteBuffer *sql = new SqliteBuffer("E:\\asdf.db"); 
    for(int i(0); i<2000; i++){ 
     sql->SaveMessage("HELLO WORLD"); 
    } 
    return 0; 
} 

我在Visual Studio 10中測試了這些代碼,它們工作正常,但插入非常慢。我在這裏錯過了什麼。

+2

由於您從不初始化'has_transaction_begun',因此程序未定義。 – molbdnilo

+0

您*必須*檢查所有'sqlite3_ *'函數的返回值。由於molbdnilo顯示錯誤,最後一個'sqlite3_exec'將失敗(因爲沒有活動事務)。 –

+0

是的,我將檢查完整代碼中的錯誤。當我製作原型時,除非速度非常慢,否則此工作正常。 – Pant

回答

2

除非您在事務中執行這些操作,否則每個查詢都會隱式發生在其自己的事務中。對於INSERT操作,這需要至少兩個flush + sync操作:一個將數據寫入日誌(回退或WAL),一個將數據寫入數據庫本身,並且可能還有一個取決於日誌類型。對文件的同步操作是非常慢,因爲它們需要操作系統清空文件的寫入緩衝區,並且等待磁盤報告數據已被寫入。

嘗試在循環之前開始事務並立即提交。你應該看到性能上的顯着提高。這種技術的缺點是,在循環中間的應用程序或系統崩潰將導致所有掛起的更改被回滾。

+0

我在代碼中添加了BeginTransaction。 – Pant

+0

@SarvagyaPant你永遠不會調用EndTransaction。 –

+0

@SarvagyaPant OFFS ...調用'BeginTransaction()'調用'SaveMessage()'_then_ call'EndTransaction()'的所有調用。 –