Poco插入大量数据到数据库的优化

最近在调试 Poco 操作数据库的性能问题,确实发现一些有意思的地方,不仅有事务方面的批量,还有容器实现的内部批量,当然先以最基础的事务模式作为开头,来进插入性能的对比测试

事务操作

一般插入数据没什么好说的,但是在数据量比较多的时候,总体的插入就会很慢,这个时候最基本的操作就是批量操作,也就是靠事务进行,比如下面的代码,以 Poco.Data.Sqlite 为例

Poco::Data::Session sess("SQLite", "test.db");
sess << "create table if not exists test ("
"[col_a] NVARCHAR(256) NOT NULL,"
"[col_b] NVARCHAR(256) NOT NULL)", Poco::Data::Keywords::now;

DWORD tick = GetTickCount();
sess.begin();
for (size_t i = 0; i < 1000000; i++) {
char bufa[64] = { 0 };
char bufb[64] = { 0 };
sprintf(bufa, "test col a %d %d", i, rand());
sprintf(bufb, "test col b %d %d", i*2, rand());

sess << "insert into test(col_a,col_b) values(?,?)",
Poco::Data::Keywords::use(bufa),
Poco::Data::Keywords::use(bufb),
Poco::Data::Keywords::now;
}

sess.commit();
DWORD n = GetTickCount() - tick;
std::cout << n << std::endl;

上面简单的生成100万数据量,简单的表,仅考察插入性能,在开始之前,取消事务(即注释掉sess.begin()sess.commit())测试一下,一分钟都没好,直接KILL程序。当你再跑一次上面的程序,耗时输出是8秒,差异特别大。

now关键字是立即执行的意思,即使放到了事务中,也是在事务中立即执行,一定不能丢掉。

容器的性能提升

如果仔细查看Poco的文档,就会发现其中支持STL容器,并且插入也是支持的,这个意思是不是就是说,直接把数据给Poco,内部会自动批处理吗?带着疑问再做一次测试

DWORD tick = GetTickCount();
std::list<std::string> a, b;
for (size_t i = 0; i < 1000000; i++) {
char bufa[64] = { 0 }; char bufb[64] = { 0 };
sprintf(bufa, "test col a %d %d", i, rand());
sprintf(bufb, "test col b %d %d", i * 2, rand());
a.push_back(bufa); b.push_back(bufb);
}

sess << "insert into test(col_a,col_b) values(?,?)",
Poco::Data::Keywords::use(a),
Poco::Data::Keywords::use(b),
Poco::Data::Keywords::now;

DWORD n = GetTickCount() - tick;
std::cout << n << std::endl;

执行起来又是看不到结束的迹象,这也印证了这并不是事务模式,可能只是某些方面的优化,是不是有优化效果呢,我们将数量改为1000,有很小的进步。那么将上面二者结合呢

容器与事务结合

通过将容器数据进行事务包装,效果有多大改观呢,为容器语句前后简单的加上事务的启动和提交代码(即增加sess.begin()sess.commit())进行对比测试,这次执行却只需要2秒多,对比前面的是8秒多,差距明显。

为了更加简单的减少字符串操作引起的差异,直接插入固定字符串,只涉及到数据库操作部分,对比之后发现效果是7秒多和1秒多,也就是说即使前面容器对操作的改观小数据量不大,但在大数据量下面的差距会被放大很多。

综述,使用容器和事务结合的方法在大数据量插入的操作下效果提升非常明显!

这里测试效果仅仅是对比效果,不要在意数字大小,毕竟使用SSD效果比机械硬盘好,表结构有诸多限制也会大大降低插入速度,总体而言上面的方法是比较快的办法,实际中的差异可根据具体的表结构和环境进行对比测试。

最近的文章

FFMPEG和SDL实现流媒体播放控件

之前为项目中使用ffmpeg与SDL封装了一个视频播放控件,用起来挺简单的,在此分享下大概的实现方法和效果。 基本需求原本项目中被C#调用了一个第三方的播放RTMP的控件,但是呢问题特别多,而且不能再定制功能,因为我接手给实现了一个,大致的需求如下 提供DLL供其他语言调用,主要是C# 支持多窗 …

技术 继续阅读
更早的文章

关于浮点数的精度问题

最近在调试 Jsoncpp 输出 Json 时候的浮点数问题,起因还是 Jsoncpp 输出精度的问题。又想起之前 java 开发同事竟然信心满满的告诉我说 double 不存在精度问题,真是感慨非C程序员对底层技术的掌握甚少。 关于浮点数一般我们把数字称为整数、小数等,但是在计算机里面我们却称呼小 …

技术 继续阅读