2

我有一个奇怪的问题,涉及使用 JDBC 将大量数据放入 PostgSQL 数据库的 executeBatch 和 Prepared Statements。我每次使用 executeBatch 向数据库发送 50,000 条语句。

我知道执行批处理和准备好的语句正在工作;一些数据正在进入数据库。准备好的语句是

  INSERT INTO time ( time_id, log_id, phenomenon_time, qc_phenomenon_time )
  SELECT nextval( 'time_seq' ), ?, ?, ?

并将其与执行批处理一起使用,可以在数据库中找到数据。

使用以下准备好的语句时,

  INSERT INTO result_3d ( result_3d_id, time_id, variable_id, value, qc_value ) 
  SELECT nextval( 'result_3d_seq' ), ( SELECT t.time_id 
                                       FROM time t 
                                       WHERE t.log_id = ? 
                                       AND t.phenomenon_time = ? ), ?, ?, ?

使用执行批处理,数据库中没有数据。我什至打开了数据库日志记录,发现第一个的所有内容,但第二个什么都没有。第二个准备好的语句依赖于第一个的数据,但数据库甚至没有看到第二个。

没有抛出异常。唯一奇怪的是,对于第二个准备好的语句,返回的数组的大小为零。执行批处理立即返回。第二个准备好的语句中的子查询是否允许?

我使用 postgres-9.1-901.jdbc4.jar 作为针对 PostgreSQL v8.3.19 数据库的 JDBC 驱动程序。

请帮忙。

4

2 回答 2

3

我将回答我自己的问题,因为我描述的症状与执行批处理或准备语句无关。在一些重构过程中,我遗漏了一个重要的声明。

this.preparedStatement.addBatch();

所以这是我的错。症状很好地描述了缺少语句的代码行为。

我感谢您在评论中所做的努力。有些人给了我新的学习领域。谢谢欧文。

于 2012-06-25T10:05:46.813 回答
2

我不知道 JDBC 驱动程序,但您使用 9.1 版并连接到过时的 PostgreSQL 8.3.19 看起来很可疑。将 PostgreSQL 升级到 9.1 可能会解决您的问题。

time.time_id通常,如果您已将列定义result_3d.result_3d_idserial列(您可能应该这样做),或者您已nextval()手动将这些列的 DEFAULT 值设置为相应的序列,则无需从序列中获取 id 。这些值将自动填写

第二个准备好的语句中的子查询是否允许?

是的,原则上是这样。但它可能永远不会返回超过一排。您必须保证唯一性(t.log_id, t.phenomenon_time)或添加LIMIT 1

(SELECT t.time_id 
 FROM time t 
 WHERE t.log_id = ? 
 AND t.phenomenon_time = ?
 LIMIT 1)

使用 PostgreSQL 9.1,您可以将这两个INSERT命令与数据修改 CTE链接在一起,这应该会更快一些,并且不需要以子查询开头:

WITH data (log_id, phenomenon_time, qc_phenomenon_time
          ,variable_id, value, qc_value ) AS (
    VALUES(?, ?, ?, ?, ?, ?)  -- cast to appropriate types!
    )
    , i AS (
    INSERT INTO time (log_id, phenomenon_time, qc_phenomenon_time)
    SELECT log_id, phenomenon_time, qc_phenomenon_time
    FROM   data
    RETURNING time_id, log_id, phenomenon_time 
    )
INSERT INTO result_3d (time_id, variable_id, value, qc_value) 
SELECT i.time_id, d.variable_id, d.value, d.qc_value
FROM   data d
JOIN   i USING (log_id, phenomenon_time);

所有这些可能会或可能不会解决根本问题,但很有可能会。

我的第一个想法是潜在的问题可能是并发问题——这意味着第二个问题INSERT是在第一个问题提交之前开始的。但是,如果数据库甚至没有看到第二次调用,那么这里肯定有其他事情在起作用。

于 2012-06-24T03:46:31.690 回答