https://www.tutorialspoint.com/hibernate/hibernate_batch_processing.htm

ользую Hibernate ORM и PostgreSQL в своем приложении, а иногда я использую пакетные операции. И сначала я не понял, почему в журналах с размером пакета = 25 генерируется 25 запросов, и сначала подумал, что он работает неправильно. Но после этого я посмотрел на исходный код драйвера pg и обнаружил следующие строки в классе PgStatement:

 public int[] executeBatch() throws SQLException {
        this.checkClosed();
        this.closeForNextExecution();
        if (this.batchStatements != null && !this.batchStatements.isEmpty()) {
            this.transformQueriesAndParameters();
//confuses next line, because we have array of identical queries
            Query[] queries = (Query[])this.batchStatements.toArray(new Query[0]);
            ParameterList[] parameterLists = 
(ParameterList[])this.batchParameters.toArray(new ParameterList[0]); 
            this.batchStatements.clear();
            this.batchParameters.clear();

и в классе PgPreparedStatement

    public void addBatch() throws SQLException {
        checkClosed();
        if (batchStatements == null) {
          batchStatements = new ArrayList<Query>();
          batchParameters = new ArrayList<ParameterList>();
        }

        batchParameters.add(preparedParameters.copy());
        Query query = preparedQuery.query;
    //confuses next line
        if (!(query instanceof BatchedQuery) || batchStatements.isEmpty()) {
          batchStatements.add(query);
        }
      }

Я заметил, что получается, что если размер пакета составляет 25, то отправляется 25 запросов с прикрепленными к ним параметрами.

Журналы базы данных подтверждают это, например:

2017-12-06 01:22:08.023 MSK [18402] [email protected] СООБЩЕНИЕ:  выполнение S_3: BEGIN
2017-12-06 01:22:08.024 MSK [18402] [email protected] СООБЩЕНИЕ:  выполнение S_4: select nextval ('tests_id_seq')
2017-12-06 01:22:08.041 MSK [18402] [email protected] СООБЩЕНИЕ:  выполнение S_2: insert into tests (name, id) values ($1, $2)     
2017-12-06 01:22:08.041 MSK [18402] [email protected] ПОДРОБНОСТИ:  параметры: $1 = 'test', $2 = '1'
2017-12-06 01:22:08.041 MSK [18402] [email protected] СООБЩЕНИЕ:  выполнение S_2: insert into tests (name, id) values ($1, $2)
2017-12-06 01:22:08.041 MSK [18402] [email protected] ПОДРОБНОСТИ:  параметры: $1 = 'test', $2 = '2'
...
x23 queries with parameters 
...
2017-12-06 01:22:08.063 MSK [18402] [email protected] СООБЩЕНИЕ:  выполнение S_5: COMMIT

Но я думал, что один запрос должен быть выполнен с массивом из 25 параметров. Или я не понимаю, как пакетные вставки работают с подготовленным оператором? Зачем дублировать один запрос n раз?

В конце концов, я пытался отлаживать свои запросы на этом месте

if (!(query instanceof BatchedQuery) || batchStatements.isEmpty()) {

и заметил, что мои запросы всегда являются экземпляром SimpleQuery, а не BatchedQuery. Может быть, это решение проблемы? Информация о BatchedQuery я не смог найти

 Mark Rotteveel06 дек. 2017 г., 17:13
Это может быть вопрос, который вам лучше задать в списке рассылки postgresql-jdbc.

Ответы на вопрос(2)

Решение Вопроса

и я расскажу о его части как JDBC-драйвере PostgreSQL (pgjdbc).

TL; DR: pgjdbc использует меньше обходов сети, если используется пакетный API.BatchedQuery используется только еслиreWriteBatchedInserts=true передается в настройки соединения pgjdbc.

Вы можете найтиhttps://www.slideshare.net/VladimirSitnikv/postgresql-and-jdbc-striving-for-high-performance соответствующие (слайд 44, ...)

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

Предположим, дело в том, чтобы вставить 10 строк.

Нет дозирования (например, простоPreparedStatement#execute в петле). Водитель будет выполнять следующее

execute query
sync <-- wait for the response from the DB
execute query
sync <-- wait for the response from the DB
execute query
sync <-- wait for the response from the DB
...

Заметное время будет потрачено на «ожидание БД»

Пакетный API JDBC. ЭтоPreparedStatement#addBatch() позволяет драйверу отправлять несколько «запросов на выполнение» в одной сети. Однако текущая реализация по-прежнему разделяет большие пакеты на более мелкие, чтобы избежать тупика TCP.

Действия были бы намного лучше:

execute query
...
execute query
execute query
execute query
sync <-- wait for the response from the DB

Обратите внимание, что даже с#addBatch, есть накладные расходы на команды «выполнить запрос». Серверу требуется определенное время для обработки каждого сообщения в отдельности.

Одним из способов уменьшить количество запросов является использование вставки с несколькими значениями. Например:

insert into tab(a,b,c) values (?,?,?), (?,?,?), ..., (?,?,?)

Этот PostgreSQL позволяет вставлять несколько строк одновременно. Недостаток в том, что у вас нет подробного (для каждой строки) сообщения об ошибке. В настоящее время Hibernate не поддерживает вставку нескольких значений.

Однако pgjdbc может переписывать обычные пакетные вставки в мульти значения на лету с 9.4.1209 (2016-07-15).

Для активации перезаписи нескольких значений необходимо добавитьreWriteBatchedInserts=true собственность соединения. Эта функция была изначально разработана вhttps://github.com/pgjdbc/pgjdbc/pull/491

Это достаточно умно, чтобы использовать 2 оператора, чтобы вставить 10 строк. Первый из них является 8-значным оператором, а второй - 2-значным оператором. Использование двух степеней позволяет pgjdbc сохранять количество отдельных операторов в здравом уме, что повышает производительность, поскольку часто используемые операторы подготавливаются сервером (см.Каков срок службы подготовленного оператора PostgreSQL на стороне сервера? )

BatchedQuery представляет такой тип многозначных операторов, так что вы увидите, что класс используется вreWriteBatchedInserts=true только случай

Недостатки функции могут включать в себя: более низкие детали как «результат партии». Например, регулярный пакет выдает «количество строк на оператор», однако в случае с несколькими значениями вы просто получаете статус «оператор завершен». Кроме того, средство перезаписи «на лету» может не выполнить синтаксический анализ некоторых операторов SQL (например,https://github.com/pgjdbc/pgjdbc/issues/1045 ).

 Vladimir Sitnikov18 февр. 2018 г., 20:01
@ Birthright, это может решить ваше дело:github.com/pgjdbc/pgjdbc/pull/1130
 Birthright17 февр. 2018 г., 17:54
Спасибо за ответ. Я протестировал свое приложение с этим флагом, производительность увеличилась во много раз с пакетными вставками. Но не все так хорошо, как оказалось. Я видел, что в последних версиях драйвера pg конструкцииничего не делать, а такжесделать обновление установить столбец = значение было исправлено. Но конструкциив случае конфликта сделать обновление установить столбец =? не работает. Понятно, что вряд ли это может привести к одному SQL-запросу. Поэтому мне пришлось отключить этот флаг.
 Vladimir Sitnikov18 февр. 2018 г., 19:18
@ Birthright, не стесняйтесь создать проблему для случая, который не работает (см.github.com/pgjdbc/pgjdbc/issues )

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

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

Больше читать здесь.

https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html https://www.tutorialspoint.com/hibernate/hibernate_batch_processing.htm

Ваш ответ на вопрос