Sqlite3常用的插入方法及性能测试

Posted liu_roy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sqlite3常用的插入方法及性能测试相关的知识,希望对你有一定的参考价值。

此篇博文是我一开始写在我的csdn(http://blog.csdn.net/roy1261/article/details/51501240)上,以后会慢慢把博文迁移到博客园

最近做到的项目涉及一个大数据量缓存重传,其中要用到的sqlite技术,把自己的学习心得整理了一下。

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。同时能够跟很多程序语言相结合,比如 Tcl、C#、php、Java等,还有ODBC接口,同样比起mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite数据库由于其简单、灵活、轻量、开源,已经被越来越多的被应用到中小型应用中。因此在许多软件中例如(QQ,微信)等许多软件中都有广泛应用。

技术分享技术分享

 

慢插入-暴力插入

技术分享

调用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 }

 

以上是关于Sqlite3常用的插入方法及性能测试的主要内容,如果未能解决你的问题,请参考以下文章

sqlite3 多线程和锁 ,优化插入速度及性能优化

Sqlite3插入大量数据性能优化

常用的性能测试方法策略及测试要点

sqlite3 性能测试 - 如何快速重置/清除缓存

ArrayList去重常用的四种方式及性能对比(JMH性能分析)

内部排序常用算法(含动图及算法性能测试程序,了解不同情况下的排序算法的选择)