当前位置: 首页 > 知识库问答 >
问题:

与SQL Server相比,MariaDB JDBC驱动程序无法有效批处理更新

穆城
2023-03-14

我对应用程序中的插入/更新/删除例程的性能进行了基准测试,我正在将该例程从SQL Server移植到MariaDB。

  • 带有i7 2.80GHz CPU+16GB RAM
  • 的本地Win10工作站上的Java 1.8
  • jdbc org.mariadb.jdbc:mariadb-java-client:2.2.4
  • 10.2.12-MariaDB-在AWS上记录MariaDB服务器

该基准触发50,000次插入、相同的更新和删除。

SQL Server通过Net.SourceForge.jtds JDBC驱动程序在1秒内处理所有这些数据。

这两个数据库中的模式都是相同的,我认为由于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 vs 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次写入只是很小的数据量--大约2MB。但是对于SQL语法,当它通过JDBC连接时,这可能要大10倍--这是正确的吗?

下面是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个答案

东方俊力
2023-03-14

在批处理中的某些行之间添加“BEGIN”和“COMMIT”语句。或者在批处理之前启动事务,然后在批处理之后提交。这将比成千上万个单独的声明要快得多。

如果您只执行插入操作,rewriteBatchStatements=true应该会大大加快它的速度,而不需要事务处理。你也可以把max_packet_size增加到1GB,这会做更多的批处理,也许你的整个批处理会被转换成1个非常大的multi-insert。

 类似资料:
  • spark-defaults.conf中没有任何内容,以编程方式初始化spark上下文的代码是: 在所有这些之后,Spark UI的Environment选项卡的Spark.driver.maxResultSize为10G,Spark.driver.memory为20G,但是驱动程序的存储内存的executors选项卡显示为0.0B/4.3GB。 (请注意:我以前的Spark.Driver.Mem

  • 我正在处理Spring Boot项目,突然遇到应用程序无法加载MySQL jdbc的问题。(我编译了一次这个项目,没有改变任何东西) 这是我的pom.xml: 这是我的application.properties: Logcat: MySQL数据库最初是使用hibernate创建的。这些配置工作正常,但我不确定这里的真正问题是什么 编辑:我删除了。m2文件夹并从一开始安装所有依赖项。

  • 问题内容: 我正在尝试运行一个ruby文件,该文件将使用seleniumwebdriver启动chrome驱动程序。我有selenium独立服务器2.35.0。和chromedriver可执行文件已安装。我正在通过运行服务器来启动 两个会话正在启动,chrome驱动程序无法启动。 这是在我使用以下文件运行文件之后 我对此并不陌生,无法找出问题所在。而且,我也试图让它无头运行,所以我正在运行Xvfb

  • 我试图运行一个ruby文件,这将启动chrome驱动程序使用selenium WebDriver。我有selenium独立服务器2.35.0。和chromedriver可执行文件安装。我通过运行来启动服务器, 这是在我使用 我对此很陌生,不知道哪里出了问题。我也试图无头运行它,所以我有Xvfb运行。有人能帮我指出我犯的错误并启动chromedriver吗? 更新: 谁能帮我弄清楚出了什么问题吗?

  • 所以我有一个在我localhost的端口8080上运行的Spring Boot应用程序。它连接到Azure sqlserver数据库并从该数据库中提取或插入项目。本地一切正常。现在我正在尝试对应用程序进行文档化。我的Dockerfile如下所示: Dockerfile位于根文件夹中,与pom的文件夹相同。xml和mssql-jdbc-9.2.1。jre15.jar文件。此jar是从Microsof

  • 问题内容: 我正在尝试使用switch来发出警报并执行操作,但是我遇到了错误。 现在真正的问题是当我将下面的代码放入try中时,catch可以正常工作。我的意思是它可以完美地处理警报。但是当我不经尝试使用相同代码时,捕获代码将引发以下异常 请在下面找到错误 问题答案: 这个想法是当您处理警报时,您必须先检查警报是否存在。我会使用这种方法: 在这里您可以获得详细信息,也不要忘记逐步调试以了解出现/不