JDBC 更新 Oracle 数据库上的数百万条记录



我有一个设计问题。我有一个包含数百万条记录的数据库,我需要更新。

我们将使用 JDBC,因为我们必须做一些处理来计算新字段值。

这是一次性的,我将不再需要它。所以我在想一些简单的事情。我想创建新表并删除旧表,但 DBA 不想这样做,因为对存储的需求将是巨大的。

我将不得不处理大约 8000 万行,并且每行更新 3 个字段。

一个简单的jdbc方法,例如setFetchSize(1000),会起作用吗?

我的意思是从可变中选择 a、b、c 进行更新; 然后更新...

JDBC 程序是否能够支持工作负载?

我也在考虑使用SpringBatch或EasyBatch。但我想知道是否值得一次性调查一下时间(以及一些非常短的时间表)。

您对此有何经验?

我认为你可以在JDBC中做到这一点。我会建议如下:

  • 创建两个或三个线程。每个线程执行以下操作
  • 创建连接。
  • 创建检索行的不相交子集的预准备语句
  • 将提取大小设置为 100 左右。绝对少于1000。
  • 创建更新语句
  • 执行查询
  • 循环访问结果集
  • 对于每一行添加批处理以更新行
  • 提取大小行后执行批处理

假设提取大小为 100。第一次执行将进行往返,这需要时间。发生这种情况时,请运行另一个线程。当执行返回处理接下来的 100 行时,不会执行数据库往返。行已被提取,并且正在批处理更新,因此这不会执行数据库往返。在 100 行后执行批处理,这将执行往返,因此将切换线程。然后它将获取另外 100 行,这将切换线程。我不确定两个或三个线程是最佳的,但如果我不得不猜测,我会尝试三个。

但是上面假设机器只有一个硬件线程,这是不正确的。大多数 CPU 支持 12 个或更多硬件线程,因此我实际上会使用 30 个左右的线程,具体取决于硬件可以支持的内容。即使有多个 CPU,您也可能不希望超过 50 个左右的线程,因为这将开始在数据库中引入争用。

上面假设外部服务很快,比数据库快得多。如果不是,则处理每一行将等待外部服务。在这种情况下,更多的线程。由于更新对数据库的命中速度会更慢,因此数据库中的线程争用不太重要。

将查询结果划分为不相交子集的一种方法如下:

SELECT c1, c2, etc, row 
FROM (SELECT c1, c2, etc, ROWNUM FROM ...) 
WHERE MOD(row, number_of_partitions) = ?

然后将查询参数设置为 0 到 number_of_partitions - 1,每个线程一个。您必须将其作为子查询才能使 ROWNUM 正常工作。

不要使用可更新的结果集。性能将是糟糕的,保证。

最新更新