2012-10-19 110 views
2

我有一个需求来编写一个批量作业,该作业从数据库表中获取行并基于特定条件写入其他表或使用特定值更新此行。我们使用spring和jdbc来获取结果集,并使用计划每周运行的独立Java程序遍历并处理记录。我知道这不是正确的做法,但我们必须作为临时解决方案。随着记录数量增加到数百万,我们最终会遇到内存不足的例外,所以我知道这不是最好的方法。在Java中处理数百万条数据库记录

你们中的任何人都可以推荐什么是处理这种情况的最佳方法?

使用线程并获取每个线程1000条记录并并行处理它们?

(OR)

使用任何其他批处理机制来做到这一点(我知道有弹簧批,但从来没有用过这个)

(OR)

任何其他的想法?

+1

这可能是一种应该在“数据仓库”中完成的工作吗?数据是否可以通过某种在线系统同时访问,例如繁忙的网站?处理结果是否需要首先创建数据的进程可访问? – Marvo

+0

大多数JDBC驱动程序不会加载查询上的整个结果集,但只会加载'fetchSize'行数。我相信只有MySQL Connector/J以不同的方式执行它,所以无论您处理多少行(假设为'FORWARD_ONLY'结果集),大多数驱动程序都不会耗尽内存。 –

+0

调查Spring Batch框架,专门为这样的东西编写。 - http://docs.spring.io/spring-batch/ – Ram

回答

6

一个批量作业,从数据库表中取出行并基于特定条件写入其他表或使用特定值更新此行。

这听起来像是你应该在数据库中做的事情。例如,要获取特定的行并根据特定条件对其进行更新,SQL具有UPDATE ... WHERE ... statement。要写入其他表格,您可以使用INSERT ... SELECT ...

这些可能会相当复杂,但我建议尽你所能地在数据库中执行此操作,因为将数据拉出来过滤它非常缓慢,并且失去了建立关系数据库的目的。

注意:确保首先在非生产系统上进行试验,并实施所需的任何限制,以免在不良时间锁定生产表。

+1

+1 - 正确。为什么要将所有网络延迟引入中间层来对其进行操作?浪费,特别是对于那么多的数据。 – duffymo

+0

感谢您的反馈,我会牢记这一点。 – user1583261

+0

理想情况下,是的。但是,如果这是你真的需要将数据带出来的话。就像使用一些专有的隐藏算法来散列数据并插入散列一样?你不能在数据库中实现它。 – ADTC

7

您已经知道您不能将一百万行记录到内存中并对其进行操作。

你必须以某种方式组装它们。

为什么把他们带到中间层?我会考虑编写存储过程并对数据库服务器上的数据进行操作。把它带到中间层似乎不像是在向你购买任何东西。让批处理作业启动存储的proc并在数据库服务器中就地执行计算。

1

这实际上取决于你处理记录的方式和方式。

但一般来说,你不应该一次加载它们到内存中,而是要处理大小合理的数据块。

0

与Brendan Long一致。但是,我可能仍然会尝试选择存储过程中“数百万”数据集的子集。否则,你会吹掉你的数据库的事务日志。只要确保您仍然定期提交您的插入或更新。

如果你不想在存储过程中这样做,只需要弹簧批量加载你想要在某个固定块大小(使用光标/分页阅读器)操作的记录的键,但获得存储proc来做实际的工作。通过这种方式,您可以最小化传递到中间层的数据,同时仍然可以获得Spring批处理和数据库操作数据的性能。

相关问题