【问题标题】:Inconsistent insert speed of batch update to temp table in MySQL (with jdbcTemplate.batchUpdate)批量更新到 MySQL 中临时表的插入速度不一致(使用 jdbcTemplate.batchUpdate)
【发布时间】:2016-04-19 17:39:49
【问题描述】:

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

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

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

谁能告诉如何让它在所有运行中运行 1-3 秒?

表定义:

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;

【问题讨论】:

  • 您确定CREATE 不会终止交易吗?
  • 桌子上没有PRIMARY KEY

标签: mysql performance mariadb


【解决方案1】:

问题是我使用了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$4.doInPreparedStatement(JdbcTemplate.java:897)
    at org.springframework.jdbc.core.JdbcTemplate$4.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)

【讨论】:

    【解决方案2】:

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

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

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

    阅读更多here

    【讨论】:

    • 它是一个临时表,因此索引不会因连续运行而增长。问题是为什么插入时间对于类似的操作会有如此大的不同。
    • 我对您的回答投了反对票,因为它对这个问题没有用处,并且感觉您发布它只是为了获得评分,而对问题细节没有太多关注。尽管您的评论让我深入挖掘执行语句的客户端代码,但我发现了问题所在。如果您最初的回答是关于它,那肯定是解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 2019-06-29
    • 2018-03-14
    • 2011-09-11
    • 2011-08-21
    • 1970-01-01
    相关资源
    最近更新 更多