首页 > 解决方案 > jOOQ 批量插入不一致

问题描述

在 jOOQ (v3.14.4) 中使用批量插入时,我注意到在查看 PostgreSQL (v12.6) 日志时存在一些不一致之处。执行context.batch(<query>).bind(<1st record>).bind(<2nd record>)...bind(<nth record>).execute()日志时,显示记录实际上是一一插入,而不是一次全部插入。从 postgres 日志来看,这样做context.insert(<fields>).values(<1st record>).values(<2nd record>)...values(<nth record>)实际上会一次性插入所有内容。它是 jOOQ 本身的错误还是我batch(...)错误地使用了该功能?

这里有 2 个代码片段应该做同样的事情,但实际上,第一个代码片段一个接一个地插入记录,而第二个代码片段实际上是批量插入。

    public void batchInsertEdges(List<EdgesRecord> edges) {
        Query batchQuery = context.insertInto(Edges.EDGES,
                Edges.EDGES.SOURCE_ID, Edges.EDGES.TARGET_ID, Edges.EDGES.CALL_SITES,
                Edges.EDGES.METADATA)
                .values((Long) null, (Long) null, (CallSiteRecord[]) null, (JSONB) null)
                .onConflictOnConstraint(Keys.UNIQUE_SOURCE_TARGET).doUpdate()
                .set(Edges.EDGES.CALL_SITES, Edges.EDGES.as("excluded").CALL_SITES)
                .set(Edges.EDGES.METADATA, field("coalesce(edges.metadata, '{}'::jsonb) || excluded.metadata", JSONB.class));
        var batchBind = context.batch(batchQuery);
        for (var edge : edges) {
            batchBind = batchBind.bind(edge.getSourceId(), edge.getTargetId(),
                    edge.getCallSites(), edge.getMetadata());
        }
        batchBind.execute();
    }
    public void batchInsertEdges(List<EdgesRecord> edges) {
        var insert = context.insertInto(Edges.EDGES,
                Edges.EDGES.SOURCE_ID, Edges.EDGES.TARGET_ID, Edges.EDGES.CALL_SITES, Edges.EDGES.METADATA);
        for (var edge : edges) {
            insert = insert.values(edge.getSourceId(), edge.getTargetId(), edge.getCallSites(), edge.getMetadata());
        }
        insert.onConflictOnConstraint(Keys.UNIQUE_SOURCE_TARGET).doUpdate()
                .set(Edges.EDGES.CALL_SITES, Edges.EDGES.as("excluded").CALL_SITES)
                .set(Edges.EDGES.METADATA, field("coalesce(edges.metadata, '{}'::jsonb) || excluded.metadata", JSONB.class))
                .execute();
    }

我会很感激一些帮助来弄清楚为什么第一个代码片段不能按预期工作而第二个代码片段可以。谢谢!

标签: javapostgresqljooq

解决方案


“批处理”(如 JDBC 批处理)和“批量处理”(如许多 RDBMS 所说的“批量更新”)之间存在差异。

有关数据导入的手册的这一页解释了差异

  • 批量大小:一条 SQL 语句中发送到服务器的行数。
  • 批处理大小:一个 JDBC 语句批处理中发送到服务器的语句数。

这些是根本不同的事情。两者都有助于提高性能。批量数据处理通过帮助 RDBMS 优化资源分配算法来实现这一点,因为它知道它将插入 10 条记录。批量数据处理通过减少客户端和服务器之间的往返次数来实现。任何一种方法是否对任何给定的 RDBMS 都有很大影响显然是特定于供应商的。

换句话说,您的两种方法都按预期工作。


推荐阅读