1

我需要在java中创建一个批处理,它将读取一个可变数量的记录文件(尽管可以安全地假设5k +),处理它们,然后将记录插入到oracle 11g数据库中。我需要通过调用存储过程来做到这一点。

几个月前我已经做了一个类似的过程,我对此并不感到太自豪(没有什么特别的原因,除了我确信它根本不是最优的)。之前的解决方案我将所有内容都保存在内存中,为了插入行,我创建了一个 INSERT ALL 语句,在该语句中我只是通过一个字符串构建器附加了所有记录,然后执行该语句以一次性插入 15k+ 条记录。这次我需要使用存储过程来插入数据。我一直在阅读,现在知道有办法将数据数组发送到存储过程,所以我可以一次发送多条记录。

我是否应该创建一个存储过程来接收数组并在一次调用该 SP 时发送所有(可能是数千条)记录?还是我应该一次将其限制为一定数量的记录并调用该 SP(记录/限制)次数?

或者我应该远离使用数组,并拥有一个只接收一条记录的信息的存储过程,并根据我的记录多次调用它?

如果我要进行多次调用,我正在考虑使用 PreparedStatements 以及 .addBatch() 和 .executeBatch() 方法,这会是可行的方法吗?

我需要能够插入所有记录,并在出现任何错误时回滚。我将为此使用事务。从技术上讲,我不需要在性能方面达到任何门槛,但我对这个话题很感兴趣,这可能是开始更多地担心它的好时机,所以我想从有这个话题经验的人那里得到一些指示和提示.

4

2 回答 2

1

"Should I make a Stored procedure that receives arrays and just send all - potentially thousands - of the records in one single call to that SP? Or should I limit it to a certain amount of records at a time and call that SP (records/limit) amount of times?"

Limit to a certain amount of records. I generally start with between 100 and 1000, depending on the total size of a record.

"Or should I stay away from using arrays, and have a stored procedure that just receives the information for one record, and call it as many times as I have records?"

No. You will waste CPU and above all time: every time Java calls the database there is time spent just on sending the message and getting the reply back (related to "latency").

"If I were to do multiple calls, I was thinking of utilizing PreparedStatements and the .addBatch() and .executeBatch() methods, would this be the way to go?"

Yes, but those methods are at their best with SQL statements (such as INSERT), not calls to stored procedures.

I need to be able to insert all the records, and rollback in case of any error.

Set autocommit off (which I recommend in general) and commit when all is OK.

If your stored procedures have no added value, but simply do the inserts, then it would be simpler and very efficient to do batched inserts. There are very good arguments for using stored procedures despite the extra complication, but then you would have to populate the arrays.

In every case, it is vital to use bind variables and not concatenate the values into the SQL statements (or calls to SPs) as literals.

Best regards, Stew Ashton

P.S. for 5k+ records, multi-threading is overkill.

于 2019-11-09T20:34:21.887 回答
0

你应该使用存储过程(SP)吗?

我认为它不会有任何显着的性能改进,因为您有一个 INSERT 语句。如果您有一些复杂的查询并且使用它可以节省查询编译时间,那么 SP 将是有益的。一个简单的插入语句不会花费太多时间来编译。

因此,在我看来,使用 Java 的 PreparedStatement 即时发送您的查询。

我会遵循的方法:

由于您的要求是插入所有数据并在出现错误时回滚,我建议您批量插入整组数据。如果批处理失败,您可以回滚批处理的更改并重试批处理插入。

如果您要一次性发送整个数据集,那么您将不得不回滚由于单个插入语句中的错误而导致的整个更改。

使用批处理的另一个好处是您将在单个 JDBC 连接中发送批处理数据。建立、维护和清除连接会产生开销。因此,批处理在一定程度上节省了开销。

此外,您可以使用多线程,您可以让任务读取一批数据,处理它们并插入它们(使用批处理)。您的任务可以从 HikariCP 等连接池访问 JDBC 连接。因此,当一些线程忙于数据插入时,其他线程可以读取和处理数据。

关于多线程插入的一些材料:https ://dba.stackexchange.com/questions/16131/how-does-oracle-handle-multiple-concurrent-inserts-against-one-table

PS:欢迎建设性批评。

于 2019-11-09T18:51:38.993 回答