• 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 }
  • 相关阅读:
    一个基础的CURL类
    设计自适应网页方法
    JQ点击列表显示隐藏
    获取当前页面的完整URL
    配置时间生成下拉菜单
    Contains Duplicate II
    Rectangle Area
    面试题47:不用加减乘除做加法
    面试题48:用C++设计一个不能被继承的类
    Reverse Linked List
  • 原文地址:https://www.cnblogs.com/liuroy/p/5616236.html
Copyright © 2020-2023  润新知