Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 更快地批量加载嵌套数据_Java_Sql_Spring_Postgresql - Fatal编程技术网

Java 更快地批量加载嵌套数据

Java 更快地批量加载嵌套数据,java,sql,spring,postgresql,Java,Sql,Spring,Postgresql,我正在填充两个表,它们具有1-many关系 因此,我在外部中插入一行,获取该行的(自动递增主键)id,然后在内部中插入100行(所有外键都指向外部.id) 然后我重复,50次。对于外部中的每个条目,我必须插入,读取id,然后插入到内部 这太慢了。大部分时间用于将100行代码加载到内部。我想如果我能在一次批处理操作中将所有50*100行插入内部,速度会快得多。但是我不知道怎么做-我怎么才能使外键工作 其他人是如何使其高效的 我正在使用Java/Spring。这100行插入了一个JdbcTempla

我正在填充两个表,它们具有1-many关系

因此,我在
外部
中插入一行,获取该行的(自动递增主键)
id
,然后在
内部
中插入100行(所有外键都指向
外部.id

然后我重复,50次。对于
外部
中的每个条目,我必须插入,读取
id
,然后插入到内部

这太慢了。大部分时间用于将100行代码加载到
内部
。我想如果我能在一次批处理操作中将所有50*100行插入
内部
,速度会快得多。但是我不知道怎么做-我怎么才能使外键工作

其他人是如何使其高效的

我正在使用Java/Spring。这100行插入了一个
JdbcTemplate.batchUpdate()

更新-以下内容似乎适用于Spring 3.1.1和Postgres 9.2-1003.jdbc4

/**
 * An alternative implementation that should be faster, since it inserts
 * in just two batches (one for inner and one fo router).
 *
 * @param db A connection to the database.
 * @param data The data to insert.
 */
public final void insertBatchier(final JdbcTemplate db,
                                 final AllDataBlocks data) {
    final List<Object[]> outers = data.getOuter();
    List<Integer> ids = db.execute(
            new PreparedStatementCreator() {
                @Override
                public PreparedStatement createPreparedStatement(
                        final Connection con) throws SQLException {
                    return con.prepareStatement(getInsertSql(),
                            Statement.RETURN_GENERATED_KEYS);
                }
            },
            new PreparedStatementCallback<List<Integer>>() {
        @Override
        public List<Integer> doInPreparedStatement(final PreparedStatement ps)
                throws SQLException {
            for (Object[] outer: outers) {
                for (int i = 0; i < outer.length; ++i) {
                    setParameterValue(ps, i + 1,
                            SqlTypeValue.TYPE_UNKNOWN, outer[i]);
                }
                ps.addBatch();
            }
            ps.executeBatch();
            RowMapperResultSetExtractor<Integer> ids =
                    new RowMapperResultSetExtractor<Integer>(
                            new ItemRowMapper.IdRowMapper());
            try (ResultSet keys = ps.getGeneratedKeys()) {
                return ids.extractData(keys);
            }
        }
    });
    innerTable.insert(db, data.getInner(ids));
}
/**
*另一种应该更快的实现,因为它插入
*只需两批(一批用于内部路由器,一批用于fo路由器)。
*
*@param db连接到数据库。
*@param data要插入的数据。
*/
公共最终void insertBatchier(最终JdbcTemplate db,
最终所有数据块(数据){
最终列表outers=data.getOuter();
List id=db.execute(
新的PreparedStatementCreator(){
@凌驾
公共PreparedStatement createPreparedStatement(
最终连接(con)引发SQLException{
返回con.prepareStatement(getInsertSql(),
语句。返回\u生成的\u键);
}
},
新的PreparedStatementCallback(){
@凌驾
公共列表未编制报表(最终编制报表ps)
抛出SQLException{
对于(对象[]外部:外部){
对于(int i=0;i
我不太熟悉
JdbcTemplate
,但假设它与JDBC类似,我会使用与以下代码类似的方法(我可能会将其分解为多个方法):

private static final int BATCH_SIZE = 50;

public void addBatch(Connection connection, List<Outer> outers) {

  PreparedStatement outerInsertStatement = connection.prepareStatement("...", Statement.RETURN_GENERATED_KEYS);
  PreparedStatement innerInsertStatement = connection.prepareStatement("...", Statement.RETURN_GENERATED_KEYS);

  List<Integer> outerIds = new ArrayList<Integer>();

  for(Outer outer : outers) {
    outerInsertStatement.setParameter(...);
    ...
    outerInsertStatement.setParameter(...);

    outerInsertStatement.addBatch();
  }

  outerInsertStatement.executeBatch();
  //Note, this line requires JDBC3
  ResultSet primaryKeys = outerInsertStatement.getGeneratedKeys();
  while(!primaryKeys.isAfterLast()) {
    outerIds.add(primaryKeys.getInt(0));
  }

  for(int i = 0; i < outers.size(); i++) {
    Outer outer = outers.get(i);
    Integer outerId = outerIds.get(i);
    for(Inner inner : outer.getInners()) {
      //One of these setParameter calls would use outerId
      innerInsertStatement.setParameter(...);
      ...
      innerInsertStatement.setParameter(...);
      innerInsertStatement.addBatch();

      if( (i+1) % BATCH_SIZE == 0) {
        innerInsertStatement.executeBatch();
      }
    }
    innerInsertStatement.executeBatch();
  }
}
private static final int BATCH\u SIZE=50;
public void addBatch(连接,列出outer){
PreparedStatement outerInsertStatement=connection.prepareStatement(“…”,Statement.RETURN\u生成的\u键);
PreparedStatement innerInsertStatement=connection.prepareStatement(“…”,Statement.RETURN\u生成的\u键);
List outerIds=new ArrayList();
用于(外部:外部){
setParameter(…);
...
setParameter(…);
outerInsertStatement.addBatch();
}
outerInsertStatement.executeBatch();
//注意,此行需要JDBC3
ResultSet primaryKeys=outerInsertStatement.getGeneratedKeys();
而(!primaryKeys.isAfterLast()){
add(primaryKeys.getInt(0));
}
对于(int i=0;i
我不明白。为什么不将
外部
中的所有记录插入一批,然后将
内部
中的所有记录插入一批?为什么不发布一些代码呢?如果我可以检索外部表中所有插入的索引,我就可以这样做。有没有办法在一系列值上检索自动递增键?我必须手动管理密钥生成吗?可能有多个线程正在向这些表中添加/删除数据。这与java代码不符,但从数据库的角度来看,您必须采用基于集合的方法,而不是逐行执行此操作,这听起来就像您当前正在执行的操作。能否将所有数据转储到postgre中的临时表中,并使用临时表作为源执行插入?这将一次性插入所有数据,这比许多微小的插入要便宜。@JustBob(谢谢)忽略java,如何设置使内部(或临时)表具有外部表的外键引用?这是我的根本问题。内部表的每100行(或多或少)引用一个不同的外部行。并且ID是自动递增的。我想我需要自己管理这些密钥。我添加了一些sql表以备不时之需。太棒了。我不知道GetGeneratedKey的存在。谢谢(环顾四周,它似乎需要一个非常新的jdbc和postgres库,但这不应该是一个问题)?我试过了(请参阅问题“更新”部分中的代码),但似乎postgres驱动程序不支持这个(在jdbc标准中是可选的)啊,不,对不起。我倾向于在MySQL中工作,没有在Postgres中工作过。在准备语句时,您可能需要执行
con.prepareStatement(sql,Statement.RETURN\u GENERATED\u key)
。我读了,忘了。哑的但你更令人敬畏。看来是这样
/**
 * An alternative implementation that should be faster, since it inserts
 * in just two batches (one for inner and one fo router).
 *
 * @param db A connection to the database.
 * @param data The data to insert.
 */
public final void insertBatchier(final JdbcTemplate db,
                                 final AllDataBlocks data) {
    final List<Object[]> outers = data.getOuter();
    List<Integer> ids = db.execute(
            new PreparedStatementCreator() {
                @Override
                public PreparedStatement createPreparedStatement(
                        final Connection con) throws SQLException {
                    return con.prepareStatement(getInsertSql(),
                            Statement.RETURN_GENERATED_KEYS);
                }
            },
            new PreparedStatementCallback<List<Integer>>() {
        @Override
        public List<Integer> doInPreparedStatement(final PreparedStatement ps)
                throws SQLException {
            for (Object[] outer: outers) {
                for (int i = 0; i < outer.length; ++i) {
                    setParameterValue(ps, i + 1,
                            SqlTypeValue.TYPE_UNKNOWN, outer[i]);
                }
                ps.addBatch();
            }
            ps.executeBatch();
            RowMapperResultSetExtractor<Integer> ids =
                    new RowMapperResultSetExtractor<Integer>(
                            new ItemRowMapper.IdRowMapper());
            try (ResultSet keys = ps.getGeneratedKeys()) {
                return ids.extractData(keys);
            }
        }
    });
    innerTable.insert(db, data.getInner(ids));
}
private static final int BATCH_SIZE = 50;

public void addBatch(Connection connection, List<Outer> outers) {

  PreparedStatement outerInsertStatement = connection.prepareStatement("...", Statement.RETURN_GENERATED_KEYS);
  PreparedStatement innerInsertStatement = connection.prepareStatement("...", Statement.RETURN_GENERATED_KEYS);

  List<Integer> outerIds = new ArrayList<Integer>();

  for(Outer outer : outers) {
    outerInsertStatement.setParameter(...);
    ...
    outerInsertStatement.setParameter(...);

    outerInsertStatement.addBatch();
  }

  outerInsertStatement.executeBatch();
  //Note, this line requires JDBC3
  ResultSet primaryKeys = outerInsertStatement.getGeneratedKeys();
  while(!primaryKeys.isAfterLast()) {
    outerIds.add(primaryKeys.getInt(0));
  }

  for(int i = 0; i < outers.size(); i++) {
    Outer outer = outers.get(i);
    Integer outerId = outerIds.get(i);
    for(Inner inner : outer.getInners()) {
      //One of these setParameter calls would use outerId
      innerInsertStatement.setParameter(...);
      ...
      innerInsertStatement.setParameter(...);
      innerInsertStatement.addBatch();

      if( (i+1) % BATCH_SIZE == 0) {
        innerInsertStatement.executeBatch();
      }
    }
    innerInsertStatement.executeBatch();
  }
}