Pet*_*sky 5 java postgresql hibernate jdbc
我在我的应用程序中使用Hibernate ORM和PostgreSQL,有时我使用批处理操作.起初我不明白为什么在批处理大小为25的日志中,会生成25个查询,并且最初认为它无法正常工作.但之后我查看了pg驱动程序的源代码,并在PgStatement类中找到以下行:
public int[] executeBatch() throws SQLException {
this.checkClosed();
this.closeForNextExecution();
if (this.batchStatements != null && !this.batchStatements.isEmpty()) {
this.transformQueriesAndParameters();
//confuses next line, because we have array of identical queries
Query[] queries = (Query[])this.batchStatements.toArray(new Query[0]);
ParameterList[] parameterLists =
(ParameterList[])this.batchParameters.toArray(new ParameterList[0]);
this.batchStatements.clear();
this.batchParameters.clear();
Run Code Online (Sandbox Code Playgroud)
并在PgPreparedStatement类中
public void addBatch() throws SQLException {
checkClosed();
if (batchStatements == null) {
batchStatements = new ArrayList<Query>();
batchParameters = new ArrayList<ParameterList>();
}
batchParameters.add(preparedParameters.copy());
Query query = preparedQuery.query;
//confuses next line
if (!(query instanceof BatchedQuery) || batchStatements.isEmpty()) {
batchStatements.add(query);
}
}
Run Code Online (Sandbox Code Playgroud)
我注意到,如果批处理的大小为25,则会发送25个查询并附加参数.
数据库的日志确认了这一点,例如:
2017-12-06 01:22:08.023 MSK [18402] postgres@buzzfactory ?????????: ?????????? S_3: BEGIN
2017-12-06 01:22:08.024 MSK [18402] postgres@buzzfactory ?????????: ?????????? S_4: select nextval ('tests_id_seq')
2017-12-06 01:22:08.041 MSK [18402] postgres@buzzfactory ?????????: ?????????? S_2: insert into tests (name, id) values ($1, $2)
2017-12-06 01:22:08.041 MSK [18402] postgres@buzzfactory ???????????: ?????????: $1 = 'test', $2 = '1'
2017-12-06 01:22:08.041 MSK [18402] postgres@buzzfactory ?????????: ?????????? S_2: insert into tests (name, id) values ($1, $2)
2017-12-06 01:22:08.041 MSK [18402] postgres@buzzfactory ???????????: ?????????: $1 = 'test', $2 = '2'
...
x23 queries with parameters
...
2017-12-06 01:22:08.063 MSK [18402] postgres@buzzfactory ?????????: ?????????? S_5: COMMIT
Run Code Online (Sandbox Code Playgroud)
但我认为必须使用25个参数的数组执行一个查询.或者我不明白批量插入如何与预准备语句一起使用?为什么要重复一次查询n次?
毕竟,我试图在这个地方调试我的查询
if (!(query instanceof BatchedQuery) || batchStatements.isEmpty()) {
Run Code Online (Sandbox Code Playgroud)
并注意到我的查询始终是SimpleQuery的实例而不是BatchedQuery.也许这是问题的解决方案?有关BatchedQuery的信息我找不到
Vla*_*kov 12
可能涉及各种类型的批处理,我将介绍PostgreSQL JDBC驱动程序(pgjdbc)的一部分.
TL; DR:在使用批处理API的情况下,pgjdbc确实使用较少的网络回合.BatchedQuery仅在reWriteBatchedInserts=true传递给pgjdbc连接设置时使用.
您可能会发现https://www.slideshare.net/VladimirSitnikv/postgresql-and-jdbc-striving-for-high-performance相关(幻灯片44,...)
在查询执行方面,网络延迟通常是经过时间的重要部分.
假设案例是插入10行.
没有批处理(例如只是PreparedStatement#execute在循环中).驱动程序将执行以下操作
execute query
sync <-- wait for the response from the DB
execute query
sync <-- wait for the response from the DB
execute query
sync <-- wait for the response from the DB
...
Run Code Online (Sandbox Code Playgroud)
值得注意的时间将花在"等待数据库"上
JDBC批处理API.这PreparedStatement#addBatch()使得驱动程序能够在单个网络往返中发送多个"查询执行".然而,当前的实现仍然会将大批量分成较小的批次以避免TCP死锁.
行动会好得多:
execute query
...
execute query
execute query
execute query
sync <-- wait for the response from the DB
Run Code Online (Sandbox Code Playgroud)请注意,即使使用#addBatch"执行查询"命令也会产生开销.服务器需要花费大量时间来单独处理每条消息.
减少查询数量的方法之一是使用多值插入.例如:
insert into tab(a,b,c) values (?,?,?), (?,?,?), ..., (?,?,?)
Run Code Online (Sandbox Code Playgroud)
这个PostgreSQL允许一次插入多行.缺点是您没有详细的(每行)错误消息.目前,Hibernate没有实现多值插入.
但是,自9.4.1209(2016-07-15)起,pgjdbc可以动态地将常规批量插入重写为多值.
要激活多值重写,您需要添加reWriteBatchedInserts=true连接属性.该功能最初是在https://github.com/pgjdbc/pgjdbc/pull/491中开发的
它足够聪明,可以使用2个语句来插入10行.第一个是8值语句,第二个是2值语句.使用2的幂使pgjdbc能够保持不同语句的数量合理,并且这可以提高性能,因为经常使用的语句是服务器准备的(请参阅PostgreSQL服务器端预处理语句的生命周期)
BatchedQuery表示那种多值语句,因此您将看到reWriteBatchedInserts=true仅在大小写中使用的类.
该功能的缺点可能包括:较低的细节作为"批处理结果".例如,常规批处理为您提供"per statement rowcount",但在多值情况下,您只需获得"语句已完成"状态.最重要的是,动态重写器可能无法解析某些SQL语句(例如https://github.com/pgjdbc/pgjdbc/issues/1045).
| 归档时间: |
|
| 查看次数: |
2480 次 |
| 最近记录: |