MySQL 中临时 table 批量更新的插入速度不一致(使用 jdbcTemplate.batchUpdate)

Inconsistent insert speed of batch update to temp table in MySQL (with jdbcTemplate.batchUpdate)

我有 MariaDb 实例和一个临时实例 table。工作流程:

  1. 开始交易
  2. 删除临时文件 table 如果存在,创建临时文件 table
  3. 使用 insert into TEMP1 (xxx,yyy) values(?,?),(?,?),(?,?),(?,?)...
  4. 向其中插入 40K 条记录
  5. 以某种方式处理此数据
  6. 结束交易

Worflow 在一个线程中执行。 问题定义:此工作流的第一个 运行 在 1-3 秒内插入 40K 条记录,所有连续的 运行s 在 30-40 秒内插入 40K。

任何人都可以告诉如何使所有 运行 的 运行 1-3 秒吗?

Table定义:

CREATE TEMPORARY TABLE IF NOT EXISTS TEMP1 (
uuid varchar(80) COLLATE utf8_unicode_ci NOT NULL,
raw_content longtext COLLATE utf8_unicode_ci NOT NULL,
security_level varchar(255) COLLATE utf8_unicode_ci NOT NULL,
key_name varchar(255) COLLATE utf8_unicode_ci NOT NULL,
stage_user_uuid varchar(80) NOT NULL,
data_type varchar(255) COLLATE utf8_unicode_ci NOT NULL,
string_value varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
integer_value bigint(20) DEFAULT NULL,
double_value double DEFAULT NULL,
date_value datetime DEFAULT NULL, 
INDEX user_uuid_idx (stage_user_uuid)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

table 上的索引数量是影响插入性能的最主要因素。 table 的索引越多,执行速度就越慢。 insert 语句是唯一不能直接受益于索引的操作,因为它没有 where 子句。

如果 table 上有索引,数据库必须确保通过这些索引也能找到新条目。出于这个原因,它必须将新条目添加到 table 上的每个索引。因此,索引的数量是插入语句成本的乘数。

要优化插入性能,保持索引数量少非常重要。

阅读更多here

问题是我使用了 jdbcTemplate.batchUpdate,它以一种非常奇怪的方式工作。我有设置 rewriteBatchedStatements=true.

第一个 运行 真正执行了这样的语句

insert into TEMP1 (xxx,yyy) values(?,?),(?,?),(?,?),(?,?);

下一条语句因不明原因一条条执行

insert into TEMP1 (xxx,yyy) values(?,?);
insert into TEMP1 (xxx,yyy) values(?,?);
insert into TEMP1 (xxx,yyy) values(?,?);

导致运行缓慢的原因。

可以在日志中看到实际语句,连接字符串后缀为:&logger=com.mysql.jdbc.log.Slf4JLogger&profileSQL=true

我最终得到了常规的准备好的语句批处理,而且效果很好。

ps.addBatch()
ps.executeBatch()
ps.clearBatch()

根本问题是 jdbcTemplate.batchUpdate 使用 JdbcUtils.supportsBatchUpdates 由于某种原因失败了。我使用 org.apache.tomcat:tomcat-jdbc:8.0.30

driver 'supportsBatchUpdates' method threw exception
java.sql.SQLException: PooledConnection has already been closed.
    at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:87)
    at com.sun.proxy.$Proxy37.getMetaData(Unknown Source)
    at org.springframework.jdbc.support.JdbcUtils.supportsBatchUpdates(JdbcUtils.java:359)
    at org.springframework.jdbc.core.JdbcTemplate.doInPreparedStatement(JdbcTemplate.java:897)
    at org.springframework.jdbc.core.JdbcTemplate.doInPreparedStatement(JdbcTemplate.java:890)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:589)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)
    at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:890)