提升SQLite数据插入效率低、速度慢的方法

SqLite3基本操作 嵌入式开发数据库:SQLite, FireBird, eXtremetDB,3万行的基于c和c++的源码,SQLite数据库,是一个非常轻量级自包含(lightweight and self-contained)的DBMS,它可移植性好,很容易使用,很小,高效而且可靠。 SQLite嵌入到使用它的应用程序中,它们共用相同的进程空间,而不是单独的一个进程。从外部看,它并不像一个RDBMS,但在进程内部,它却是完整的,自包含的数据库引擎。 嵌入式数据库的一大好处就是在你的程序内部不需要网络配置,也不需要管. 阅读详情

**

前言

**
SQLite数据库由于其简单、灵活、轻量、开源,已经被越来越多的被应用到中小型应用中。甚至有人说,SQLite完全可以用来取代c语言中的文件读写操作。因此我最近编写有关遥感数据处理的程序的时候,也将SQLite引入进来,以提高数据的结构化程度,并且提高大数据的处理能力(SQLite最高支持2PB大小的数据)。但是最开始,我发现,直接使用SQL语句的插入效率简直低的令人发指的。后来不断查文档、查资料,才发现了一条快速的“数据插入”之路。本文就以插入数据为例,整合网上和资料书中的各种提高SQLite效率的方法,给出提高SQLite数据插入效率的完整方法。(大神们勿喷)

1 数据

实验之前,先建立要插入数据的表:
create table t1 (id integer , x integer , y integer, weight real)

2 慢速——最粗暴的方法

SQLite的API中直接执行SQL的函数是:

int sqlite3_exec( sqlite3*, const char sql, int (callback)(void,int,char*,char**), void , char **errmsg)
直接使用INSERT语句的字符串进行插入,程序部分代码(完整代码见后文),如下:
for(int i=0;i<nCount;++i)
{
std::stringstream ssm;
ssm<<“insert into t1 values(”<<i<<","<<i
2<<","<<i/2<<","<<i*i<<")";
sqlite3_exec(db,ssm.str().c_str(),0,0,0);
}
这个程序运行的太慢了,我已经没时间等待了,估算了一下,基本上是 7.826 条/s

3 中速——显式开启事务

所谓”事务“就是指一组SQL命令,这些命令要么一起执行,要么都不被执行。在SQLite中,每调用一次sqlite3_exec()函数,就会隐式地开启了一个事务,如果插入一条数据,就调用该函数一次,事务就会被反复地开启、关闭,会增大IO量。如果在插入数据前显式开启事务,插入后再一起提交,则会大大提高IO效率,进而加数据快插入速度。
开启事务只需在上述代码的前后各加一句开启与提交事务的命令即可:
sqlite3_exec(db,“begin;”,0,0,0);
for(int i=0;i<nCount;++i)
{
std::stringstream ssm;
ssm<<“insert into t1 values(”<<i<<","<<i2<<","<<i/2<<","<<ii<<")";
sqlite3_exec(db,ssm.str().c_str(),0,0,0);
}
sqlite3_exec(db,“commit;”,0,0,0);
显式开启事务后,这个程序运行起来明显快很多,估算效率达到了34095条/s,较原始方法提升约5000倍。

4 高速——写同步(synchronous)

我要使用一个遥感处理算法处理10000*10000的影像,中间有一步需要插入100000000条数据到数据库中,如果按照开启事务后的速度34095条/s,则需要100000000÷34095 = 2932秒 = 48.9分,仍然不能够接受,所以我接着找提升速度的方法。终于,在有关讲解SQLite配置的资料中,看到了“写同步”选项。

在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分。

5 极速——执行准备

虽然写同步设为off后,速度又有小幅提升,但是仍然较慢。我又一次踏上了寻找提高SQLite插入效率方法的道路上。终于,我发现,SQLite执行SQL语句的时候,有两种方式:一种是使用前文提到的函数sqlite3_exec(),该函数直接调用包含SQL语句的字符串;另一种方法就是“执行准备”(类似于存储过程)操作,即先将SQL语句编译好,然后再一步一步(或一行一行)地执行。如果采用前者的话,就算开起了事务,SQLite仍然要对循环中每一句SQL语句进行“词法分析”和“语法分析”,这对于同时插入大量数据的操作来说,简直就是浪费时间。因此,要进一步提高插入效率的话,就应该使用后者。

“执行准备”主要分为三大步骤:
1.调用函数
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<nCount;++i)  
{         
    sqlite3_reset(stmt);  
    sqlite3_bind_int(stmt,1,i);  
    sqlite3_bind_int(stmt,1,i*2);  
    sqlite3_bind_int(stmt,1,i/2);  
    sqlite3_bind_double(stmt,1,i*i);  
}  
sqlite3_finalize(stmt);  
sqlite3_exec(db,"commit;",0,0,0);  
此时测试数据插入效率为:265816条/s,也就是说,插入100000000条数据,需要376秒 = 6.27分。这个速度已经很满意了。

5 总结

综上所述啊,SQLite插入数据效率最快的方式就是:事务+关闭写同步+执行准备(存储过程),如果对数据库安全性有要求的话,就开启写同步。

附全部代码
#include
#include
#include
#include <time.h>
#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<nCount;++i)  
{  
    // std::stringstream ssm;  
    // ssm<<"insert into t1 values("<<i<<","<<i*2<<","<<i/2<<","<<i*i<<")";  
    // sqlite3_exec(db,ssm.str().c_str(),0,0,0);  
    sqlite3_reset(stmt);  
    sqlite3_bind_int(stmt,1,i);  
    sqlite3_bind_int(stmt,2,i*2);  
    sqlite3_bind_int(stmt,3,i/2);  
    sqlite3_bind_double(stmt,4,i*i);  
    sqlite3_step(stmt);  
}  
sqlite3_finalize(stmt);  
sqlite3_exec(db,"commit;",0,0,0);  
clock_t t2 = clock();  
  
sqlite3_close(db);  
  
std::cout<<"cost tima: "<<(t2-t1)/1000.<<"s"<<std::endl;  
  
return 0;  

}

优化SQLite数据库读写速度的技巧 然而,有时候我们可能会遇到一些性能方面的问题,特别是在处理大量数据时。为了提高SQLite数据库的读写速度,我们可以采取一些优化技巧。然而,有时候我们可能会遇到一些性能方面的问题,特别是在处理大量数据时。为了提高SQLite数据库的读写速度,我们可以采取一些优化技巧。综上所述,通过使用事务、批量插入、索引、预编译语句和适当的缓存策略,我们可以提高Qt中使用SQLite数据库的读写速度。综上所述,通过使用事务、批量插入、索引、预编译语句和适当的缓存策略,我们可以提高Qt中使用SQLite数据库的读写速度。 阅读详情

相关推荐

SQLITE数据库 UPDATE慢

SQLITE数据库 UPDATE慢,此为一个实例,供大家!

sqlite3往表中导入数据

1.进入sqlite 2.用命令查看数据库中表数据(.table命令) 3.执行导入数据

weixin_44235861的博客 979

从零到英雄:如何用FPGA和AD9288打造你的第一台便携式示波器

本文详细介绍了如何利用FPGA和AD9288 ADC芯片从零开始打造一台高性能便携式示波器。通过硬件架构设计、高速数据采集系统实现及信号处理与显示系统的开发,读者可以掌握400Msps采样率的实现方法,并了解关键器件选型与系统优化技巧。

jjj34的博客 277

[转载]提升SQLite数据插入效率低、速度慢的方法

[-] 前言 数据 慢速最粗暴的方法 本文为本人原创,请尊重个人劳动成果 未经本人允许,严禁转载! 0 前言 SQLite数据库由于其简单、灵活、轻量、开源,已经被越来越多的被应用到中小型应用中。甚至有人说,SQLite完全可以用来取代c语言中的文件读写操作。因此我最近编写有关遥感数据处理的程序的时候,也将SQLite引入进来,以提高数据的结...

anren7769的博客 134

利用ANSYS随机振动分析功能实现随机疲劳分析

本文介绍了ANSYS随机振动分析功能,以及利用该功能,按照Steinberg提出的基于高斯分布和Miner线性累计损伤定律的三区间法进行ANSYS随机疲劳计算的具体过程。在工程应用中,汽车、飞行器、船舶以及其它各种机械或零部件,大多是在随机载荷作用下工作,当它们承受的应力水平较高,工作达到一定时间后,经常会突然发生随机疲劳破坏,往往造成灾难性的后果。因此,预测结构或零部件的随机疲劳寿命是非常有必要的。在工程界,疲劳计算广泛采用名义应力法,即以S-N曲线为依据进行寿命估算的方法,可以直接得到总寿命。

qq_38220914的博客 7608

Win11家庭版如何让Win+R运行CMD默认管理员权限?3种方法实测有效

本文针对Win11家庭版用户,实测了三种让Win+R运行CMD默认获取管理员权限的有效方法。通过分析UAC机制与家庭版功能限制,详细介绍了注册表编辑、快捷方式创建与任务计划程序三种方案的原理、步骤与风险对比,帮助用户根据安全与效率需求选择最佳方案,实现一键高效管理。

sat99的博客 1270
上一篇: JSON读写文件的例子
下一篇: 安装SQLSERVER EXPRESS 2012失败解决方法
fugaoting
博客等级 码龄20年 0粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值