2

我需要编写一个批处理作业,该作业从数据库表中获取行并根据特定条件写入其他表或使用特定值更新该行。我们使用 spring 和 jdbc 来获取结果集,并使用计划每周运行的独立 java 程序遍历和处理记录。我知道这不是正确的做法,但我们不得不将其作为临时解决方案。随着记录增长到数百万,我们最终会出现内存不足的异常,所以我知道这不是最好的方法。

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

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

(或者)

使用任何其他批处理机制来执行此操作(我知道有 spring-batch 但从未使用过)

(或者)

还有其他想法吗?

4

4 回答 4

7

你已经知道你不能将一百万行带入内存并对其进行操作。

你必须以某种方式将它们分块。

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

于 2012-10-19T17:20:04.117 回答
6

从数据库表中获取行并根据特定条件写入其他表或使用特定值更新该行的批处理作业。

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

这些可能会变得相当复杂,但我建议尽你所能在数据库中执行此操作,因为将数据拉出以过滤它非常慢,并且违背了拥有关系数据库的目的。

注意:确保首先在非生产系统上对此进行试验,并实施您需要的任何限制,这样您就不会在糟糕的时候锁定生产表。

于 2012-10-19T17:21:49.343 回答
1

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

但一般来说,您不应该一次将它们全部加载到内存中,而是使用合理大小的块进行处理。

于 2012-10-19T17:20:14.057 回答
0

总体上同意 Brendan Long 的观点。但是,我可能仍会尝试在存储过程中选择“数百万”数据集的子集。否则,您将炸毁数据库的事务日志。只要确保您仍然定期提交插入或更新。

如果您不想在存储过程中执行此操作,只需让弹簧批量加载您希望以某个固定块大小操作的记录的键(使用游标/分页阅读器),但让存储过程执行实际工作。通过这种方式,您可以最大限度地减少传递到中间层的数据,同时仍然获得弹簧批处理的好处和您的数据库在处理数据方面的性能。

于 2012-10-19T18:42:07.267 回答