在java中并行读取/处理结果集

时间:2016-10-23 08:09:02

标签: java jdbc java-8 java-stream resultset

我有这个要求迭代结果集中返回的数百万条记录并处理它们并将它们存储在某些数据结构中。我无法找到任何相关的相关示例或参考。 JOOQ似乎正在做我可能想要的事情,但似乎它不是免费的。我希望如果使用java 8流我可能能够实现它,但不是示例或写入似乎给了我任何方向前进。我也对其他选择持开放态度。
基于这个SO参考:resultset parallel我在下面尝试过,但它没有给我任何性能改进,如下面的性能指标所示。
代码: 顺序迭代:

while(rs.next()) {
    System.out.println(rs.getString(1));
    }

使用流和分裂器:

Stream<String> s = StreamSupport.stream(new Spliterators.AbstractSpliterator<String>(Long.MAX_VALUE,
                Spliterator.ORDERED) {

            @Override
            public boolean tryAdvance(Consumer<? super String> action) {
                try {
                    if (!rs.next())
                        return false;
                    action.accept(rs.getString(1));
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return true;
            }
        }, true);
        s.forEach(System.out::println);

总记录数:3759
顺序所需时间:~83.8秒左右 Streams花费的时间:~83.5秒

任何人都可以查看这个并告诉我,我是否未正确实施流。

1 个答案:

答案 0 :(得分:4)

无法并行处理ResultSet。它是一种迭代器,包含必须针对查询更改的可变状态,最值得注意的是,ResultSet具有必须移动的当前行,然后才能读取。即使对于通过索引访问的行中的值,规范也没有提供线程安全保证,并且提到了底层数据库可能不支持无序读取它们的可能性。

因此,可以从并行处理中受益的唯一操作是链接后续操作,但是当唯一的链接操作是System.out::println时,会使情况变得更糟。打印操作不仅不会受益于并行处理,所有标准实现都在PrintStreamSystem.out,它将使每个写操作与目标输出同步。

请注意,即使您链接计算密集型操作(可能受益于并行处理),仍然可能昂贵的数据库操作占据整个执行时间。这就是为什么在将数据传输到Java端之前让数据库尽可能地过滤和/或聚合数据很重要...