Oracle to Postgres数据传输

use*_*989 2 java oracle postgresql jdbc

几年前,我写了一个小实用程序,用于将数据从Oracle数据库移动到Postgres数据库.我使用Java和JDBC来实现这一点,因为我希望Java处理预准备语句中用于执行插入的数据的数据格式.该实用程序的原始版本假定两个数据库中的表名和列名相同.更高版本接受了映射文件来处理名称差异.这个实用程序在我的组织中受到了很大的打击,但不幸的是,它没有扩展.它每小时移动大约一百万行.我们现在有30多万行的表,没有人愿意等待30个小时来传输数据.

下面的方法是实用程序的核心,也是它不能扩展的原因.此方法对每列数据执行一次,因此会调用它(num_rows*num_cols次).使用分析器,我发现此方法占用了58%的执行时间.单独的getObject()和findColumn()调用占执行时间的53%!

    public void setPlaceholderValue ( int placeHolderNum, ResultSet rs, String oracleColumnName, PreparedStatement stmt ) throws Exception {

    int columnIndex = rs.findColumn(oracleColumnName) ;
    int columnType = rs.getMetaData().getColumnType(columnIndex) ;

    try{
        if ( rs.getObject(oracleColumnName) != null ){
            switch (columnType) {
                case Types.VARCHAR: stmt.setString(placeHolderNum,  rs.getString(columnIndex)); break;
                case Types.INTEGER:   stmt.setInt(placeHolderNum, rs.getInt(columnIndex)); break ;
                case Types.DATE:       stmt.setDate(placeHolderNum, rs.getDate(columnIndex)); break;
                case Types.FLOAT:      stmt.setFloat(placeHolderNum, rs.getFloat(columnIndex)); break ;
                case Types.NUMERIC:  stmt.setBigDecimal(placeHolderNum,rs.getBigDecimal(columnIndex)); break ;
                case Types.TIMESTAMP:      stmt.setTimestamp(placeHolderNum, rs.getTimestamp(columnIndex)); break ;
                default: throw new SQLException("The result set column type " +  rs.getMetaData().getColumnType(columnIndex) + " was not recognized. see the java.sql.Types class at http://java.sun.com/j2se/1.5.0/docs/api/ ");
            }
        } else {
            stmt.setNull(placeHolderNum, columnType);
        }
    } catch (SQLException e){
        System.out.println ("SQLException: " + e.getMessage() + " for record id=" + rs.getLong("id"));
        throw new SQLException("rethrow");
    }
}
Run Code Online (Sandbox Code Playgroud)

我不确定我是否可以重构这种方法来充分缩短转移时间.我认为逐列方法根本无法扩展.

谁能建议更好的方法呢?语言不是问题,我可以用任何可以处理工作的东西来做.理想情况下,我希望每小时至少有1000万条记录的传输速率.

Bal*_*usC 5

我建议使用DB提供的导出/导入工具.Oracle和PostgreSQL支持XML和CSV格式.

如果你想坚持使用JDBC,那么将列放在SELECT查询中的ResultSet顺序与INSERT查询中的值相同PreparedStatement,只需执行以下操作而不是整个if/switch块:

preparedStatement.setObject(index, resultSet.getObject(index));
Run Code Online (Sandbox Code Playgroud)

但是,我不认为这会大大提高性能.DB提供的导出/导入功能可以比Java中的功能更高效.

  • 借调了。实现此目的的最佳方法(恕我直言)是针对 Oracle 表编写查询,将数据映射到 PostgreSQL 表并运行这些查询来创建 CSV 文件。然后,使用 PostgreSQL COPY 命令导入数据。在这一点上,每小时 10M 行不算什么——我通常会在 PostgreSQL 中将 28M 行导入到单个表中,构建索引,并派生出两个聚合表。 (2认同)