PostgreSQL jdbc batch insert

标签

PostgreSQL , jdbc , batch , addbatch , executebatch , insert


背景

如何快速的将数据导入数据库?

比如ETL程序,数据还原程序,数据初始化,数据同步等场景都会有这样的诉求。

从几个方面来分析

1. 统计信息

PostgreSQL会自动统计表的统计信息,包括柱状图等。会有一定的开销,所以在做批量导入时,可以先关闭表的autovacuum.

2. 索引

构造索引,会有一定的CPU和IO开销,影响导入速度,所以可以在数据导入后再建索引。

3. 约束

约束会耗费一定的CPU,也可以在数据导入后再加索引。

4. 检查点

数据库导入势必产生WAL日志,如果WAL很多,可能会产生检查点,影响IO。因此可以把检查点的时间拉长(设置ckpt target, timeout)。

5. COMMIT fsync

如果是单条INSERT的导入方式,并且使用了autocommit,那么每条COMMIT都会导致FSYNC,flush wal。从而降低速度。

可以设置为异步提交,降低RT。

或者使用批量提交,例如100条提交一次。

6. parser开销

insert需要parser, 即使使用绑定变量,也有诸多tuple form的工作。

使用copy 接口可以提高效率。

7. 交互次数

如果使用的是单条insert,也有批量的方式提高速度,例如insert into table values (),(),(),.....;

相比以下,减少了交互次数,可以大幅提升性能,与COPY效率类似。

begin;
insert into table values ();
insert into table values ();
...
end;

8. 10.0即将推出的一个新特性,将允许libpq有批量提交QUERY的功能。

《PostgreSQL 10.0 preview 性能增强 - libpq支持pipeline batch模式减少网络交互提升性能》

本文将要讲一下jdbc的batch insert.

jdbc batch insert

目前,使用jdbc prepared statement insert与addbatch, execute batch,你可能会发现,最后SQL还是没有封装成这样insert into table values (),(),(),.....;而是一条一条的insert。

社区也有类似的讨论帖子

Hi,  

As document said, in the extended query protocol, "The query string
contained in a Parse message cannot include more than one SQL
statement".  

So to support batch in prepared statement, I think the only way is to
determine the batch size in advance and then create the appropriate
prepared statement, e.g.  

Given the batch size is fixed to 3, then prepare below statement:
-- create table foobar(a int, b text);
insert into foobar values($1, $2), ($3, $4), ($5, $6);  

Then this prepared statement must be bound with 3 set of arguments.  

The limitation is obvious: the batch size is fixed, so if you need to
do batch with size of 4, the previous prepared statement is useless
and you need to recreate it.  

On the other hand, in JDBC, it seems that you just need to prepare
below statement:  

insert into foobar values($1, $2);  

And then calls addBatch() repeatedly until you think the batch size is enough.  

What's the final statement does postgresql jdbc driver convert to? I'm
so curious.  

I'm not familiar with jdbc, and although I check the driver source
codes, but I still cannot understand it.  

Anybody knows the answer? Thanks.  

Regards,
Jinhua Luo

github里面有一个JDBC batch insert rewrite功能,可以将single batch转换为multi-row batch

https://github.com/whitingjr/batch-rewrite-statements-perf

The first measures INSERT statements in a single batch  

 batch begin
  | INSERT
  | INSERT
  | INSERT
  | INSERT
  | n INSERT
 batch end
the second uses an individual multi-row INSERT statement.  

INSERT INTO orderline VALUES (?,?),(?,?),(?,?),(?,?),(n,n)
Both types has 3 individual benchmarks with varying numbers of statement/row. There is a benchmark called SMALL, MEDIUM and LARGE. The count for each is configurable. See Configuration section later for details.

下面是测试对比,很显然multi-row的效果好很多。

建议要么使用multi-row batch,要么使用copy.

jdbc 版本

可以看到multi-row batch已经支持了,在这

https://github.com/pgjdbc/pgjdbc/commit/510e6e0fec5e3a44ffda854f5cf808ce9f72ee2e

fix: improve insert values(...) batch rewrite
Now it supports VALUES (?,1), and splits very long batch into series of smaller ones
to keep overall number of bind variables <32768 (that is PG's limit in v3 protocol)

Trigger property: reWriteBatchedInserts=true. Default value is still "false".

closes #580
closes #584

用法

reWriteBatchedInserts=true

参考

《PostgreSQL 10.0 preview 性能增强 - libpq支持pipeline batch模式减少网络交互提升性能》

https://jdbc.postgresql.org/

https://github.com/pgjdbc/pgjdbc/

https://www.postgresql.org/message-id/55130DC8.2070508@redhat.com

https://github.com/pgjdbc/pgjdbc/pull/491

https://www.postgresql.org/message-id/flat/CAAc9rOwTZ3d6%3DYUV-vJPndebVyUGAz_Pk8WV1fYkmpVykttLug%40mail.gmail.com#CAAc9rOwTZ3d6=YUV-vJPndebVyUGAz_Pk8WV1fYkmpVykttLug@mail.gmail.com

https://jdbc.postgresql.org/documentation/publicapi/index.html

时间: 2024-05-20 12:17:45

PostgreSQL jdbc batch insert的相关文章

实战 Eclipse ,Jigloo, PostgreSQL,JDBC 开发数据库查询应用系统起步

数据|数据库 实战 Eclipse ,Jigloo, PostgreSQL,JDBC 开发数据库查询应用系统起步 1 安装 Eclipse笔者用的GNU/Linux先从 下载了些GTK+相关的包编译安装之后,到Eclipse主页上 找到了Linux下GTK的 Eclipse安装文件 2 .插件笔者安装了两个插件一个是GUI设计工具 jigloo,主页:http://cloudgarden.com/jigloo/ 一个是打包工具 fat jar exporterhttp://fjep.source

如何解决could not execute jdbc batch update?

问题描述 如何解决could not execute jdbc batch update.本人是菜鸟不知道此问题那里出错,请教.谢谢! 解决方案 1.因为Hibernate Tools(或者Eclipse本身的Database Explorer)生成*.hbn.xml工具中包含有catalog="***"(*表示数据库名称)这样的属性,将该属性删除就可以了2.估计是你的列名里面有关键字的原因吧,命名列的时候不要单独使用date,ID...这种关键字 Hibernate查询时候的问题.莫

hibernate错误:IllegalArgumentException以及Could not execute JDBC batch update

首先第一种错误:org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of redwine.vo.WineUser.id 通过异常信息可以看出来是非法的属性.提示非法的属性,通过查看实体类中属性和配置文件,发现实体类中属性被我修改过,但是其中的setter方法还没有修改过来,所以系统找不到,也就非法了. 第二种错误:Could not execute JDBC b

PostgreSQL upsert功能(insert on conflict do)的用法

标签 PostgreSQL , upsert , insert on conflict do 背景 PostgreSQL 9.5 引入了一项新功能,UPSERT(insert on conflict do),当插入遇到约束错误时,直接返回,或者改为执行UPDATE. 语法如下 Command: INSERT Description: create new rows in a table Syntax: [ WITH [ RECURSIVE ] with_query [, ...] ] INSER

postgresql 源码 insert 返回字段说明

--当我们插入一条数据到数据库时,pg会返回给我们如下信息, postgres=# insert into test_2(id) select n from generate_series(1,10000) n; INSERT 0 10000 --第一列说明是插入动作,第三列表示插入了多少行,那么第二列是什么呐 --查看源码,可知 ProcessQuery(PlannedStmt *plan, const char *sourceText, ParamListInfo params, DestR

请教:org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch ...

问题描述 org.hibernate.exception.SQLGrammarException:CouldnotexecuteJDBCbatchupdateatorg.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)atorg.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)atorg.hiber

轨迹系统 需求分析与DB设计

标签 PostgreSQL , PostGIS , 快递 , 包裹侠 , 地理位置 , 距离排序 , KNN 背景 物流行业对地理位置信息数据的处理有非常强烈的需求,例如 1. 实时跟踪快递员.货车的位置信息.对数据库的写入性能要求较高. 2. 对于当日件,需要按发货位置,实时召回附近的快递员. 3. 实时的位置信息非常庞大,为了数据分析的需求,需要保留数据,所以需要廉价的存储.例如对象存储.同时还需要和数据库或分析型的数据库产品实现联动. 阿里云的 PostgreSQL + HybridDB

PostgreSQL 如何实现批量更新、删除、插入

标签 PostgreSQL , 批量 , batch , insert , update , delete , copy 背景 如何一次插入多条记录? 如何一次更新多条记录? 如何一次批量删除多条记录? 批量操作可以减少数据库与应用程序的交互次数,提高数据处理的吞吐量. 批量插入 批量插入1 使用insert into ... select的方法 postgres=# insert into tbl1 (id, info ,crt_time) select generate_series(1,1

求批量插入和更新Excel导入数据高效解决方法~

问题描述 需求:导入Excel(上万条记录),每一行数据对应表(table_product)的一条记录. 导入时先读取Excel,并将数据insert到table_product表,同时insert到记录表,当barcode存在则做update操作.(barcode是Excel中的某一列的值).现有的处理方式很脑残:Action处理: List<String[]> list = new ArrayList<String[]>(); Map<Integer, String[]&