使用sqlite3_exec 插入100万行数据需要 27 s,而使用sqlite3_bind_double 插入100万行数据只需要3.7 s。
主要是因为采用sqlite3_exec(),相当于每插入一行数据同时用到sqlite3_prepare_v2(), sqlite3_step() 和 sqlite3_finalize(),另外需要把double 强制转换成 string 然后再转换成 const char*,这也需要耗费时间;而如果采用sqlite3_bind_double来加入数据,只要用到sqlite3_prepare_v2(),然后不断地使用sqlite3_step() 和 sqlite3_reset();并且不需要数据类型的转换。
当然,BEGIN TRANSACTION 的功能居功至伟。如果把sqlite3_exec(database,"BEGIN TRANSACTION;",NULL,NULL,&errmsg); 和 sqlite3_exec(database,"COMMIT TRANSACTION;",NULL,NULL,NULL); 这两行注释掉,那么上述两种方法将耗费大量的时间;需要几分钟吧?
关于不同插入方法对插入速度的影响,见http://www.sqlite.org/faq.html#q19 中的“(19) INSERT is really slow - I can only do few dozen INSERTs per second”
下面是两种类型的代码:
使用sqlite3_exec 插入100万行数据
#include <iostream> #include <iostream> #include "sqlite3.h" #include <string.h> #include <stdio.h> #include <sys/time.h> #include <boost/lexical_cast.hpp> using namespace std; using namespace boost; int first_row; sqlite3* database; // callback function; int select_callback(void *p_data, int num_fields, char **p_fields, char **p_col_names) { int i; int* nof_records = (int*) p_data; (*nof_records)++; // first_row was defined in <select_stmt> function; // if first_row == 1, print the first row // and then set first_row = 0 to avoid the subsequent execution for the following rows. if (first_row == 1) { first_row = 0; for (i=0; i < num_fields; i++) { // printf("%20s", p_col_names[i]); } // printf("\n"); for (i=0; i< num_fields*10; i++) { // printf("="); } // printf("\n"); } for(i=0; i < num_fields; i++) { if (p_fields[i]) { // printf("%20s", p_fields[i]); } else { // printf("%20s", " "); } } // printf("\n"); return 0; } // With callback function; void select_stmt(const char* stmt) { char *errmsg; int ret; int nrecs = 0; first_row = 1; ret = sqlite3_exec(database, stmt, select_callback, &nrecs, &errmsg); if(ret!=SQLITE_OK) { printf("Error in select statement %s [%s].\n", stmt, errmsg); } else { printf("\n %d records returned.\n", nrecs); } } //time caculation long timecacul () { struct timeval tv; struct timezone tz; gettimeofday(&tv,&tz); return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } int main() { long starttime, endtime, resulttime; char *errmsg; sqlite3_open("./Database.db", &database); // sqlite3_exec(database, "PRAGMA synchronous = OFF", 0, 0, &errmsg); sqlite3_stmt* stmt; string s = "create table wujie (x decimal(5,2), y decimal(5,2), z decimal(5,2))"; const char *creatTable = s.c_str(); cout << "creatTable : " << creatTable << endl; // char creatTable[] = "create table wujie (a, b, c)"; int result = sqlite3_exec ( database, creatTable, // stmt 0, 0, &errmsg ); if ( result != SQLITE_OK ) { cout << "\nCould not prepare statement: creatTable: " << result << endl; return 1; } ////////BEGIN TRANSACTION starttime=timecacul(); sqlite3_exec(database,"BEGIN TRANSACTION;",NULL,NULL,&errmsg); string insertDataStr; double x, y, z; double yTimes = 1.222222222; int iNum; for ( iNum = 1; iNum <= 1000000; iNum++ ) { x = 1 * iNum; y = yTimes * iNum; z = 2 * iNum; insertDataStr = "insert into wujie VALUES(" + lexical_cast<string>(x) + "," + lexical_cast<string>(y) + "," + lexical_cast<string>(z) + ")"; // cout << "insertDataStr: " << insertDataStr << endl; const char* insertDataChar = insertDataStr.c_str(); result = sqlite3_exec ( database, insertDataChar, // stmt 0, 0, &errmsg ); if ( result != SQLITE_OK ) { cout << "\nCould not prepare statement: inserData: " << result << endl; return 1; } } sqlite3_exec(database,"COMMIT TRANSACTION;",NULL,NULL,NULL); endtime=timecacul(); resulttime=endtime-starttime; printf("NO AUTOCOMMIT INSERT:%dms.",resulttime); cout << endl; char selectData[] = "Select x,y,z from wujie"; starttime=timecacul(); select_stmt(selectData); endtime=timecacul(); resulttime=endtime-starttime; printf("Select SQL time:%dms.",resulttime); sqlite3_close(database); return 0; }
使用sqlite3_bind_double 插入100万行数据
#include <iostream> #include <iostream> #include "sqlite3.h" #include <string.h> #include <stdio.h> #include <sys/time.h> #include <boost/lexical_cast.hpp> using namespace std; using namespace boost; int first_row; sqlite3* database; // callback function; int select_callback(void *p_data, int num_fields, char **p_fields, char **p_col_names) { int i; int* nof_records = (int*) p_data; (*nof_records)++; // first_row was defined in <select_stmt> function; // if first_row == 1, print the first row // and then set first_row = 0 to avoid the subsequent execution for the following rows. if (first_row == 1) { first_row = 0; for (i=0; i < num_fields; i++) { // printf("%20s", p_col_names[i]); } printf("\n"); for (i=0; i< num_fields*10; i++) { // printf("="); } // printf("\n"); } for(i=0; i < num_fields; i++) { if (p_fields[i]) { // printf("%20s", p_fields[i]); } else { // printf("%20s", " "); } } // printf("\n"); return 0; } // With callback function; void select_stmt(const char* stmt) { char *errmsg; int ret; int nrecs = 0; first_row = 1; ret = sqlite3_exec(database, stmt, select_callback, &nrecs, &errmsg); if(ret!=SQLITE_OK) { printf("Error in select statement %s [%s].\n", stmt, errmsg); } else { printf("\n %d records returned.\n", nrecs); } } //time caculation long timecacul () { struct timeval tv; struct timezone tz; gettimeofday(&tv,&tz); return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } int main() { long starttime, endtime, resulttime; char *errmsg; sqlite3_open("./Database.db", &database); sqlite3_stmt* stmt; string s = "create table wujie (x , y , z )"; const char *creatTable = s.c_str(); // cout << "creatTable : " << creatTable << endl; int result = sqlite3_exec ( database, creatTable, // stmt 0, 0, &errmsg ); if ( result != SQLITE_OK ) { cout << "\nCould not prepare statement: creatTable: " << result << endl; return 1; } if ( sqlite3_prepare ( database, "insert into wujie values (:x,:y,:z)", // stmt -1, // If than zero, then stmt is read up to the first nul terminator &stmt, 0 // Pointer to unused portion of stmt ) != SQLITE_OK ) { printf("\nCould not prepare statement."); return 1; } int index1, index2, index3; index1 = sqlite3_bind_parameter_index(stmt, ":x"); index2 = sqlite3_bind_parameter_index(stmt, ":y"); index3 = sqlite3_bind_parameter_index(stmt, ":z"); // cout << index1 << endl; // cout << index2 << endl; // cout << index3 << endl; printf("\nThe statement has %d wildcards\n", sqlite3_bind_parameter_count(stmt)); starttime=timecacul(); sqlite3_exec(database,"BEGIN TRANSACTION;",NULL,NULL,&errmsg); double x, y, z; double yTimes = 1.222222222; int iNum; for ( iNum = 1; iNum <= 1000000; iNum++ ) { x = 1 * iNum; y = yTimes * iNum; z = 2 * iNum; if (sqlite3_bind_double (stmt, index1, // Index of wildcard x ) != SQLITE_OK) { printf("\nCould not bind double.\n"); return 1; } if (sqlite3_bind_double (stmt, index2, // Index of wildcard y ) != SQLITE_OK) { printf("\nCould not bind double.\n"); return 1; } if (sqlite3_bind_double (stmt, index3, // Index of wildcard z ) != SQLITE_OK) { printf("\nCould not bind double.\n"); return 1; } if (sqlite3_step(stmt) != SQLITE_DONE) { printf("\nCould not step (execute) stmt.\n"); return 1; } sqlite3_reset(stmt); } sqlite3_exec(database,"COMMIT TRANSACTION;",NULL,NULL,NULL); endtime=timecacul(); resulttime=endtime-starttime; printf("NO AUTOCOMMIT INSERT:%dms.",resulttime); /////////////////////////////////////////////// starttime=timecacul(); char selectData[] = "Select * from wujie"; select_stmt(selectData); sqlite3_close(database); endtime=timecacul(); resulttime=endtime-starttime; printf("NO AUTOCOMMIT INSERT:%dms.",resulttime); return 0; }