Мне нужно сделать большое количество вставок, то есть двузначных миллионов, в Oracle-DB с использованием JDBC.Для этого я использую что-то вроде следующего класса, вдохновленного Эффективным способом сделать пакетные INSERTS с JDBC :
public class Inserter {
private final int batchSize;
private final Connection con; // with .setAutoCommit(false)
private final PreparedStatement ps;
private int currentSize = 0;
public Inserter(Connection con, PreparedStatement ps, int batchSize) {
this.con = con;
this.ps = ps;
this.batchSize = batchSize;
}
public void addInsert(Object[] vals) throws SQLException {
ps.clearParameters(); // should be redundant, but better safe than sorry
for (int i = 0; i < val.length; i++) {
this.ps.setObject(i + 1, vals[i]);
}
ps.addBatch();
currentSize++;
if (currentSize >= batchSize) {
ps.executeBatch();
currentSize = 0;
}
}
public void flush() {/** to flush leftovers */}
}
Хотя этот способ вставки работает отлично, он оченьмедленный. Производительность пакетной вставки JDBC описывает, как в основном эта точная проблема может быть решена для MySQL, поскольку, однако, rewriteBatchedStatements
, похоже, не существует в Oracle, здесь это не сильно поможет.
для повышения производительности Я также пытался переключить оператор на один большой оператор INSERT ALL ...
/ INSERT APPEND ...
в соответствии с Oracle 11g - наиболее эффективным способом вставки нескольких строк , который сделал все еще медленнее.
Таким образом, мой вопрос был бы: есть ли способ оптимизировать эти вставки, кроме простого использования addBatch()
и executeBatch()
?Или есть какая-то грубая, неэффективная ошибка в классе Inserter
выше?Любая помощь будет принята с благодарностью.
Более, возможно, полезная информация:
Таблицы, в которые нужно вставить, разбиты с количеством строк от одного до десяти миллионов наpartition.
Существует уникальное ограничение для таблиц, выглядящих примерно так: unique(id1, id2, id3, id4)
, где все столбцы в нем имеют тип NUMBER
и дополнительно связаны ограничениями внешнего ключа с первичными ключами.в других таблицах.
РЕДАКТИРОВАТЬ:
Следуя предложениям из комментариев, я переключил setObject(index, val)
вызов на:
setInt(index, val)
, setFloat(index, val)
, ...
, setNull(index, type)
вызовы, где это уместно
setObject(index, val, type)
и setNull(index, typR)
Ни одна из версий не улучшила производительность значительно.
Кроме того, я попытался вставить данные в промежуточную таблицу без каких-либо ограничений, что также не привело к повышению производительности.
Для сравнения экспортируем данные в CSV и загружаем их при помощиSQL * Loader приводит к значительному увеличению производительности, то есть ~ 4.5k => ~ 50k + строк в секунду для самой медленной таблицы 1 .
Это заставляет меня полагать, что узкое место связано с JDBC.
1 Увы, использование SQL * Loader не является (желательным) вариантом в моем конкретном случае.