Драйвер JDBC MariaDB не выполняет пакетную загрузку обновлений по сравнению с SQL Server - PullRequest
0 голосов
/ 22 мая 2018

Я проверил производительность подпрограммы вставки / обновления / удаления в моем приложении, которую я переносил с SQL Server на MariaDB.

  • Java 1.8 на локальной рабочей станции Win10 с процессором i7 2.80 ГГц + 16 ГБ ОЗУ
  • JDBC org.mariadb.jdbc: mariadb-java-client: 2.2.4
  • 10.2.12-MariaDB-log Сервер MariaDB на AWS

В тесте запускаются 50 000 вставок, те же обновления и удаления.

SQL Server через драйвер JDBC net.sourceforge.jtds обрабатывает их все за менее чем 1 секунду.

MariaDB с драйвером MariaDB-java-client выполняет вставки быстрее, но обновления (и удаления) намного медленнее - 3,5 с.

Схема одинакова в обеих базах данных,и я предполагаю, что, поскольку вставки в MariaDB выполняются быстро, это, вероятно, исключает проблему индексации или неверную конфигурацию сервера.

Я пробовал несколько вариантов строки подключения JDBC, в результате чего она оказалась самой быстрой:

  ?verifyServerCertificate=true\
  &useSSL=true\
  &requireSSL=true\
  &allowMultiQueries=true\
  &cachePrepStmts=true\
  &cacheResultSetMetadata=true\
  &cacheServerConfiguration=true\
  &elideSetAutoCommits=true\
  &maintainTimeStats=false\
  &prepStmtCacheSize=50000\
  &prepStmtCacheSqlLimit=204800\
  &rewriteBatchedStatements=false\
  &useBatchMultiSend=true\
  &useBatchMultiSendNumber=50000\
  &useBulkStmts=true\
  &useLocalSessionState=true\
  &useLocalTransactionState=true\
  &useServerPrepStmts=true

Производительность в mysql и с mysql-connectorj была во всех случаях хуже, чем в mariadb.

Я смотрю на это уже неделю и думаю об использовании рабочего места.Обходы, предложенные в моем предыдущем вопросе Как мне увеличить скорость большой серии ОБНОВЛЕНИЙ в MySQL против SQL Server?

На случай, если это может быть неправильная конфигурация сервера, вот что яМы получили ключевые переменные:

key_buffer_size                16MB
innodb_buffer_pool_size        24GB (mem 30GB)
innodb_log_file_size           134MB
innodb_log_buffer_size         8MB
innodb_flush_log_at_trx_commit 0
max_allowed_packet             16MB

Мои 50 000 записей - это лишь крошечные объемы данных - около 2 МБ.Но с синтаксисом SQL это, вероятно, в 10 раз больше, когда он проходит через соединение JDBC - это правильно?

Вот планы SQL и объяснения:

Describe `data`
+---------------+------------------+------+-----+---------------------+-------------------------------+
| Field         | Type             | Null | Key | Default             | Extra                         |
+---------------+------------------+------+-----+---------------------+-------------------------------+
| parentId      | int(10) unsigned | NO   | PRI | NULL                |                               |
| modifiedDate  | date             | NO   | PRI | NULL                |                               |
| valueDate     | date             | NO   | PRI | NULL                |                               |
| value         | float            | NO   |     | NULL                |                               |
| versionstamp  | int(10) unsigned | NO   |     | 1                   |                               |
| createdDate   | datetime         | YES  |     | current_timestamp() |                               |
| last_modified | datetime         | YES  |     | NULL                | on update current_timestamp() |
+---------------+------------------+------+-----+---------------------+-------------------------------+

INSERT INTO `data` (`value`, `parentId`, `modifiedDate`, `valueDate`) VALUES (4853.16314229298,52054,'20-Apr-18','28-Dec-18')

+------+-------------+-------+------+---------------+------+---------+------+------+-------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
|    1 | INSERT      | data  | ALL  | NULL          | NULL | NULL    | NULL | NULL | NULL  |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+



UPDATE `data` SET `value` = 4853.16314229298 WHERE `parentId` = 52054 AND `modifiedDate` = '20-Apr-18' AND `valueDate` = '28-Dec-18'

+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|    1 | SIMPLE      | data  | range | PRIMARY       | PRIMARY | 10      | NULL |    1 | Using where |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+


DELETE FROM `data` WHERE `parentId` = 52054 AND `modifiedDate` = '20-Apr-18' AND `valueDate` = '29-Jan-16'

+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|    1 | SIMPLE      | data  | range | PRIMARY       | PRIMARY | 10      | NULL |    1 | Using where |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+

[ОБНОВЛЕНИЕ]

Использование JDBC - это урезанная версия, поэтому извините за любыевопиющие ошибки:

    final Connection connection = dataSource.getConnection();
    connection.setAutoCommit(false);
    try (PreparedStatement statement = connection.prepareStatement(
                 "UPDATE data SET value = ? " +
                         "WHERE parentId = ? " +
                         "AND modifiedDate = ? " +
                         "AND valueDate = ? ")) {
        // timeSeries is a list of 50,000 data points
        Arrays.stream(timeSeries)
                .forEach(ts -> {
            try {
                statement.setDouble(1, value);
                statement.setLong(2, parentId);
                statement.setDate(3, new java.sql.Date(
                        modifiedDate.getTime()));
                statement.setDate(4, new java.sql.Date(
                        valueDate.getTime()));
                statement.addBatch();
            } catch (SQLException e) {
                throw new RuntimeException(
                        "Bad batch statement handling", e);
            }
        });
        int[] results = statement.executeBatch();
        connection.commit();
    } catch (SQLException e) {
        connection.rollback();
        throw e;
    } finally {
        connection.close();
    }

У меня также есть некоторые данные из general_log, показывающие входящие вызовы JDBC, и это выглядит довольно просто - вызов «prepare» для настройки оператора, а затем отдельные обновления.

Это то, что меня удивляет - похоже, нет дозирования:

13/06/2018 15:09    service_user_t[service_user_t] @  [9.177.2.31]  75954   298206495   Query   set autocommit=0
13/06/2018 15:09    service_user_t[service_user_t] @  [9.177.2.31]  75954   298206495   Prepare UPDATE `data` SET `value` = ? WHERE `parentId` = ? AND `modifiedDate` = ? AND `valueDate` = ?
13/06/2018 15:09    service_user_t[service_user_t] @  [9.177.2.31]  75954   298206495   Execute UPDATE `data` SET `value` = ? WHERE `parentId` = ? AND `modifiedDate` = ? AND `valueDate` = ?
13/06/2018 15:09    service_user_t[service_user_t] @  [9.177.2.31]  75954   298206495   Execute UPDATE `data` SET `value` = ? WHERE `parentId` = ? AND `modifiedDate` = ? AND `valueDate` = ?
13/06/2018 15:09    service_user_t[service_user_t] @  [9.177.2.31]  75954   298206495   Execute UPDATE `data` SET `value` = ? WHERE `parentId` = ? AND `modifiedDate` = ? AND `valueDate` = ?
13/06/2018 15:09    service_user_t[service_user_t] @  [9.177.2.31]  75954   298206495   Execute UPDATE `data` SET `value` = ? WHERE `parentId` = ? AND `modifiedDate` = ? AND `valueDate` = ?
13/06/2018 15:09    service_user_t[service_user_t] @  [9.177.2.31]  75954   298206495   Execute UPDATE `data` SET `value` = ? WHERE `parentId` = ? AND `modifiedDate` = ? AND `valueDate` = ?
etc
etc

1 Ответ

0 голосов
/ 23 мая 2018

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

Если вы только делаете вставки, rewriteBatchStatements = true должно значительно ускорить его, без транзакций.Также вы можете также увеличить max_packet_size до 1 ГБ, это увеличит пакетирование, возможно, весь пакет будет преобразован в 1 очень большую мульти-вставку.

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