Sqlite3常用的插入方法及性能測試


最近做到的項目涉及一個大數據量緩存重傳,其中要用到的sqlite技術,把自己的學習心得整理了一下。

SQLite,是一款輕型的數據庫,是遵守ACID的關系型數據庫管理系統,它包含在一個相對小的C庫中。同時能夠跟很多程序語言相結合,比如 Tcl、C#、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開源的世界著名數據庫管理系統來講,它的處理速度比他們都快。SQLite數據庫由於其簡單、靈活、輕量、開源,已經被越來越多的被應用到中小型應用中。因此在許多軟件中例如(QQ,微信)等許多軟件中都有廣泛應用。

 

sqlite應用蠻廣泛的,小到app應用,大到服務器緩存。不同的插入方法有不同的優劣,在實際開發過程中,不要一味的追求快,而忽視了安全性。下面我就介紹幾種我在這段學習過程中所了解的插入方式。

慢插入-暴力插入

調用sqlite3_exec()函數,會隱式地開啟了一個事務,其次,sqlite3_exec() 是sqlite3_perpare(),sqlite3_step(),  sqlite3_finalize()的一個結合,每調用一次這個函數,就會重復的執行這三條語句,對於相同的語句,其中sqlite3_perpare相當於編譯sql語句,如果語句相同且重復操作,就會增加很多重復操作。如果插入一條數據,就調該函數一次,事務就會被反復地開啟、關閉,會增大IO量。所以當大批量數據插入時,此方法簡直無法忍受。

 

事務插入-顯示的開啟事務

所謂”事務“就是指一組SQL命令,這些命令要么一起執行,要么都不被執行。如果在插入數據前顯式開啟事務,插入后再一起提交,

則會大大提高IO效率,進而加數據快插入速度

 

同步關閉模式-synchronous = OFF

 

當synchronous設置為FULL, SQLite數據庫引擎在緊急時刻會暫停以確定數據已經寫入磁盤。這使系統崩潰或電源出問題時能確保數據庫在重起后不會損壞。FULL synchronous很安全但很慢。

當synchronous設置為NORMAL, SQLite數據庫引擎在大部分緊急時刻會暫停,但不像FULL模式下那么頻繁。 NORMAL模式下有很小的幾率(但不是不存在)發生電源故障導致數據庫損壞的情況。但實際上,在這種情況 下很可能你的硬盤已經不能使用,或者發生了其他的不可恢復的硬件錯誤。

當設置為synchronous OFF時,SQLite在傳遞數據給系統以后直接繼續而不暫停。若運行SQLite的應用程序崩潰, 數據不會損傷,但在系統崩潰或寫入數據時意外斷電的情況下數據庫可能會損壞。另一方面,在synchronous OFF時 一些操作可能會快50倍甚至更多。在SQLite 2中,缺省值為NORMAL.而在3中修改為FULL。

 

執行前准備-sqlite3_prepare_v2

此方法就是“執行准備”(類似於存儲過程)操作,即先將SQL語句編譯好,然后再一步一步(或一行一行)地執行。如果采用前者的話,就算開起了事務,SQLite仍然要對循環中每一句SQL語句進行“詞法分析”和“語法分析”,這對於同時插入大量數據的操作來說,簡直就是浪費時間。因此,要進一步提高插入效率的話,就應該使用此方法

測試結果展示

附上源代碼

復制代碼
  1 extern "C"
  2 {
  3     #include "sqlite3.h"
  4 };
  5 
  6 #include<sstream>
  7 #include <string>
  8 #include <iostream>
  9 #include <stdlib.h>
 10 #include <ctime>
 11 #include<windows.h>
 12 
 13 
 14 #define MAX_TEST_COUNT 200
 15 
 16 using namespace std;
 17 
 18 
 19 int main()
 20 {
 21     char cmdCreatTable[256] = "create table SqliteTest (id integer , x integer , y integer, weight real)" ;
 22     sqlite3* db = NULL;
 23     char * errorMessage = NULL;
 24     int iResult = sqlite3_open("SqliteTest.db", &db);
 25     do
 26     {
 27         if (SQLITE_OK != iResult)
 28         {
 29             cout<<"創建InsertTest.db文件失敗"<<endl;
 30             break;
 31         }
 32 
 33         sqlite3_exec(db,"drop table if exists SqliteTest",0,0,0);  
 34 
 35         iResult = sqlite3_exec(db, cmdCreatTable, NULL, NULL, &errorMessage);
 36         if (SQLITE_OK != iResult)
 37         {
 38             cout<<"創建表SqliteTest失敗"<<endl;
 39             break;
 40         }
 41         DWORD timeStart;
 42         DWORD timeStop;
 43         timeStart = GetTickCount();
 44         for (int i = 0; i< MAX_TEST_COUNT; ++i)
 45         {
 46             stringstream ssm;  
 47             ssm<<"insert into SqliteTest values("<<i<<","<<i*2<<","<<i/2<<","<<i*i<<")"; 
 48             iResult = sqlite3_exec(db,ssm.str().c_str(),0,0,0); 
 49         }
 50         timeStop = GetTickCount();
 51         cout<< "直接Insert"<<MAX_TEST_COUNT<<"條數據操作執行時間" << timeStart<<"結束時間:"<<timeStop<<"共耗時:"<<timeStop-timeStart<<"ms"<<endl;
 52 
 53         timeStart = GetTickCount();
 54         sqlite3_exec(db,"PRAGMA synchronous = OFF; ",0,0,0);   
 55         for(int i = MAX_TEST_COUNT; i < MAX_TEST_COUNT*2; ++i)  
 56         {  
 57             stringstream ssm;  
 58             ssm<<"insert into SqliteTest values("<<i<<","<<i*2<<","<<i/2<<","<<i*i<<")";  
 59             sqlite3_exec(db,ssm.str().c_str(),0,0,0);  
 60         } 
 61         timeStop = GetTickCount();
 62 
 63         cout<< "同步寫關閉+直接Insert"<<MAX_TEST_COUNT<<"條數據操作執行時間" << timeStart<<"結束時間:"<<timeStop<<"共耗時:"<<timeStop-timeStart<<"ms"<<endl;
 64 
 65 
 66         timeStart = GetTickCount();
 67         sqlite3_exec(db,"PRAGMA synchronous = FULL; ",0,0,0); 
 68         sqlite3_exec(db,"begin;",0,0,0);  
 69         for(int i= MAX_TEST_COUNT*2; i< MAX_TEST_COUNT*3; ++i)  
 70         {  
 71             stringstream ssm;  
 72             ssm<<"insert into SqliteTest values("<<i<<","<<i*2<<","<<i/2<<","<<i*i<<")";  
 73             sqlite3_exec(db,ssm.str().c_str(),0,0,0);  
 74         }  
 75         sqlite3_exec(db,"commit;",0,0,0); 
 76         timeStop = GetTickCount();
 77         cout<< "事務Insert"<<MAX_TEST_COUNT<<"條數據操作執行時間"<< timeStart<<"結束時間:"<<timeStop<<"共耗時:"<<timeStop-timeStart<<"ms"<<endl;
 78 
 79 
 80         timeStart = GetTickCount();
 81         sqlite3_exec(db,"PRAGMA synchronous = OFF; ",0,0,0);  
 82         sqlite3_exec(db,"begin;",0,0,0);  
 83         for(int i = MAX_TEST_COUNT*3; i < MAX_TEST_COUNT*4; ++i)  
 84         {  
 85             stringstream ssm;  
 86             ssm<<"insert into SqliteTest values("<<i<<","<<i*2<<","<<i/2<<","<<i*i<<")";  
 87             sqlite3_exec(db,ssm.str().c_str(),0,0,0);  
 88         }  
 89         sqlite3_exec(db,"commit;",0,0,0); 
 90         timeStop = GetTickCount();
 91 
 92         cout<< "事務+同步寫關閉Insert"<<MAX_TEST_COUNT<<"條數據操作執行時間" << timeStart<<"結束時間:"<<timeStop<<"共耗時:"<<timeStop-timeStart<<"ms"<<endl;
 93 
 94         timeStart = GetTickCount();
 95         //sqlite3_exec(db,"PRAGMA synchronous = FULL; ",0,0,0); 
 96         sqlite3_exec(db,"begin;",0,0,0);  
 97         sqlite3_stmt *stmt;  
 98         const char* sql = "insert into SqliteTest values(?,?,?,?)";  
 99         sqlite3_prepare(db,sql,strlen(sql),&stmt,0);  
100         for(int i = MAX_TEST_COUNT*4; i<MAX_TEST_COUNT*5; ++i)  
101         {         
102             sqlite3_reset(stmt);  
103             sqlite3_bind_int(stmt,1,i);  
104             sqlite3_bind_int(stmt,2,i*2);  
105             sqlite3_bind_int(stmt,3,i/2);  
106             sqlite3_bind_double(stmt,4,i*i);  
107             sqlite3_step(stmt); 
108          }  
109          sqlite3_finalize(stmt);  
110          sqlite3_exec(db,"commit;",0,0,0);  
111 
112          timeStop = GetTickCount();
113          cout<< "事務+執行准備+同步寫關閉Insert"<<MAX_TEST_COUNT<<"條數據操作執行時間:"<< timeStart<<"結束時間:"<<timeStop<<"共耗時:"<<timeStop-timeStart<<"ms"<<endl;
114 
115 
116     }while(0);
117 
118     cout<<"插入測試結束"<<endl;
119     Sleep(2000);
120     sqlite3_close(db);
121     system("pause");
122     
123 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM