Пару лет назад я написал небольшую утилиту для перемещения данных из базы данных Oracle в базу данных Postgres.Я использовал Java и JDBC для этого, потому что я хотел, чтобы Java обрабатывала форматирование данных, используемых в подготовленном операторе для вставки.Исходная версия утилиты предполагала, что имена таблиц и столбцов были одинаковыми в обеих базах данных.Более поздние версии приняли файл сопоставления для обработки различий в именах.Эта утилита имела большой успех в моей организации, но, к сожалению, она не масштабировалась.Максимальная скорость составляет около миллиона строк в час.Теперь у нас есть таблицы с 30+ миллионами строк, и никто не готов ждать 30 часов для передачи своих данных.
Метод, приведенный ниже, является сердцем утилиты и причиной ее не масштабирования.Этот метод выполняется один раз для каждого столбца данных, поэтому он вызывается (num_rows * num_cols times).С профилировщиком я вижу, что этот метод потребляет 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");
}
}
Я не уверен, что смогу реорганизовать этот метод для достаточного сокращения времени передачи.Я думаю, что подход столбец за столбцом просто не масштабируется.
Кто-нибудь может предложить лучший способ сделать это?Язык не проблема, я могу сделать это с любым, что может справиться с работой.В идеале я хотел бы видеть скорость передачи не менее 10 миллионов записей в час.