Оптимизация пакетных вставок oracle jdbc - PullRequest
0 голосов
/ 30 января 2019

Мне нужно сделать большое количество вставок, то есть двузначных миллионов, в 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) вызов на:

  1. setInt(index, val), setFloat(index, val), ..., setNull(index, type) вызовы, где это уместно

  2. setObject(index, val, type) и setNull(index, typR)

Ни одна из версий не улучшила производительность значительно.

Кроме того, я попытался вставить данные в промежуточную таблицу без каких-либо ограничений, что также не привело к повышению производительности.

Для сравнения экспортируем данные в CSV и загружаем их при помощиSQL * Loader приводит к значительному увеличению производительности, то есть ~ 4.5k => ~ 50k + строк в секунду для самой медленной таблицы 1 .

Это заставляет меня полагать, что узкое место связано с JDBC.

1 Увы, использование SQL * Loader не является (желательным) вариантом в моем конкретном случае.

1 Ответ

0 голосов
/ 26 июля 2019

вы никогда не делаете коммит.Если возможно добавить коммит после executeBatch, если запрос не зафиксирован, вы создадите большие сегменты отката, которые могут замедлить работу базы данных.Также удалите ps.clearParameters (), так как вы всегда перезаписываете все параметры или ни одного.Лучше использовать Специализированную версию сеттера вместо setObject

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...