MySQL 中临时 table 批量更新的插入速度不一致(使用 jdbcTemplate.batchUpdate)
Inconsistent insert speed of batch update to temp table in MySQL (with jdbcTemplate.batchUpdate)
我有 MariaDb 实例和一个临时实例 table。工作流程:
- 开始交易
- 删除临时文件 table 如果存在,创建临时文件 table
- 使用
insert into TEMP1 (xxx,yyy) values(?,?),(?,?),(?,?),(?,?)...
向其中插入 40K 条记录
- 以某种方式处理此数据
- 结束交易
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)
我有 MariaDb 实例和一个临时实例 table。工作流程:
- 开始交易
- 删除临时文件 table 如果存在,创建临时文件 table
- 使用
insert into TEMP1 (xxx,yyy) values(?,?),(?,?),(?,?),(?,?)...
向其中插入 40K 条记录
- 以某种方式处理此数据
- 结束交易
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)