本文為本人原創,請尊重個人勞動成果
sqlite資料庫由於其簡單、靈活、輕量、開源,已經被越來越多的被應用到中小型應用中。甚至有人說,sqlite完全可以用來取代c語言中的檔案讀寫操作。因此我最近編寫有關遙感資料處理的程式的時候,也將sqlite引入進來,以提高資料的結構化程度,並且提高大資料的處理能力(sqlite最高支援2pb大小的資料)。但是最開始,我發現,直接使用sql語句的插入效率簡直低的令人髮指的。後來不斷查文件、查資料,才發現了一條快速的「資料插入」之路。本文就以插入資料為例,整合網上和資料書中的各種提高sqlite效率的方法,給出提高sqlite資料插入效率的完整方法。(大神們勿噴)
我使用的電腦是win7 64位系統,使用vc2010編譯,sqlite版本為3.7.15.2 ,電腦cpu為二代i3處理器,記憶體6g。實驗之前,先建立要插入資料的表:
create table t1 (id integer , x integer , y integer, weight real)
sqlite的api中直接執行sql的函式是:
直接使用insert語句的字串進行插入,程式部分**(完整**見後文),如下:int sqlite3_exec( sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg)
for(int i=0;i7.826 條/s
3 中速——顯式開啟事務
所謂」事務「就是指一組sql命令,這些命令要麼一起執行,要麼都不被執行。在sqlite中,每呼叫一次sqlite3_exec()函式,就會隱式地開啟了乙個事務,如果插入一條資料,就呼叫該函式一次,事務就會被反覆地開啟、關閉,會增大io量。如果在插入資料前顯式開啟事務,插入後再一起提交,則會大大提高io效率,進而加資料快插入速度。
開啟事務只需在上述**的前後各加一句開啟與提交事務的命令即可:
sqlite3_exec(db,"begin;",0,0,0);
for(int i=0;i
顯式開啟事務後,這個程式執行起來明顯快很多,估算效率達到了34095條/s,較原始方法提公升約5000倍。4 高速——寫同步(synchronous)
我要使用乙個遙感處理演算法處理10000*10000的影像,中間有一步需要插入100000000條資料到資料庫中,如果按照開啟事務後的速度34095條/s,則需要100000000÷34095 = 2932秒 = 48.9分,仍然不能夠接受,所以我接著找提公升速度的方法。終於,在有關講解sqlite配置的資料中,看到了「寫同步」選項。5 極速——執行準備在sqlite中,資料庫配置的引數都由編譯指示(pragma)來實現的,而其中synchronous選項有三種可選狀態,分別是full、normal、off。這篇部落格以及官方文件裡面有詳細講到這三種引數的設定。簡要說來,full寫入速度最慢,但保證資料是安全的,不受斷電、系統崩潰等影響,而off可以加速資料庫的一些操作,但如果系統崩潰或斷電,則資料庫可能會損毀。
sqlite3中,該選項的預設值就是full,如果我們再插入資料前將其改為off,則會提高效率。如果僅僅將sqlite當做一種臨時資料庫的話,完全沒必要設定為full。在**中,設定方法就是在開啟資料庫之後,直接插入以下語句:
sqlite3_exec(db,"pragma synchronous = off; ",0,0,0);此時,經過測試,插入速度已經變成了
41851條/s,也就是說,插入100000000條資料,需要2389秒 = 39.8分。
雖然寫同步設為off後,速度又有小幅提公升,但是仍然較慢。我又一次踏上了尋找提高sqlite插入效率方法的道路上。終於,我發現,sqlite執行sql語句的時候,有兩種方式:一種是使用前文提到的函式sqlite3_exec(),該函式直接呼叫包含sql語句的字串;另一種方法就是「執行準備」(類似於儲存過程)操作,即先將sql語句編譯好,然後再一步一步(或一行一行)地執行。如果採用前者的話,就算開起了事務,sqlite仍然要對迴圈中每一句sql語句進行「詞法分析」和「語法分析」,這對於同時插入大量資料的操作來說,簡直就是浪費時間。因此,要進一步提高插入效率的話,就應該使用後者。「執行準備」主要分為三大步驟:
1.呼叫函式關於執行準備的api的具體語法,詳見官方文件。本文中執行準備的c++**如下:並且宣告乙個指向sqlite3_stmt物件的指標,該函式對引數化的sql語句zsql進行編譯,將編譯後的狀態存入ppstmt中。int sqlite3_prepare_v2( sqlite3 *db, const char *zsql, int nbyte, sqlite3_stmt **ppstmt, const char **pztail);
2.呼叫函式 sqlite3_step() ,這個函式就是執行一步(本例中就是插入一行),如果函式返回的是sqlite_row則說明仍在繼續執行,否則則說明已經執行完所有操作;
3.呼叫函式 sqlite3_finalize(),關閉語句。
sqlite3_exec(db,"begin;",0,0,0);
sqlite3_stmt *stmt;
const char* sql = "insert into t1 values(?,?,?,?)";
sqlite3_prepare_v2(db,sql,strlen(sql),&stmt,0);
for(int i=0;i265816條/s,也就是說,插入100000000條資料,需要376秒 = 6.27分。這個速度已經很滿意了。
5 總結
綜上所述啊,sqlite插入資料效率最快的方式就是:事務+關閉寫同步
+執行準備(儲存過程)
,如果對資料庫安全性有要求的話,就開啟寫同步。
1. sqlite官方文件:附最終完整**:2.《解決sqlite3插入資料很慢的問題》:
3.《the definitive guide to sqlite》apress出版:
(這是本好書)
#include #include #include #include #include "sqlite3.h"
const int ncount = 500000;
int main (int argc,char** argv)
{ sqlite3* db;
sqlite3_open("testdb.db" ,&db);
sqlite3_exec(db,"pragma synchronous = off; ",0,0,0);
sqlite3_exec(db,"drop table if exists t1",0,0,0);
sqlite3_exec(db,"create table t1(id integer,x integer,y integer ,weight real)",0,0,0);
clock_t t1 = clock();
sqlite3_exec(db,"begin;",0,0,0);
sqlite3_stmt *stmt;
const char* sql = "insert into t1 values(?,?,?,?)";
sqlite3_prepare_v2(db,sql,strlen(sql),&stmt,0);
for(int i=0;i
sqlite插入資料效率提公升解決方案
sqlite插入效率對比 建表 create table if not existstttable id integer primary key autoincrement,name varchar 100 筆者電腦配置 硬碟是250g三星ssd硬碟 cpu os 記憶體如下 理論 sqlite 插...
sqlite提公升效率
前言 sqlite資料庫由於其簡單 靈活 輕量 開源,已經被越來越多的被應用到中小型應用中。甚至有人說,sqlite完全可以用來取代c語言中的檔案讀寫操作。因此我最近編寫有關遙感資料處理的程式的時候,也將sqlite引入進來,以提高資料的結構化程度,並且提高大資料的處理能力 sqlite最高支援2p...
提公升SQLite資料插入效率低 速度慢的方法
sqlite資料庫由於其簡單 靈活 輕量 開源,已經被越來越多的被應用到中小型應用中。甚至有人說,sqlite完全可以用來取代c語言中的檔案讀寫操作。因此我最近編寫有關遙感資料處理的程式的時候,也將sqlite引入進來,以提高資料的結構化程度,並且提高大資料的處理能力 sqlite最高支援2pb大小...