为什么Spring的jdbcTemplate.batchUpdate()这么慢?

2022-09-01 06:24:48

我试图找到更快的方法来进行批量插入

我试图用jdbcTemplate.update(String sql)插入几个批处理,其中sql是由StringBuilder构建的,看起来像这样:

INSERT INTO TABLE(x, y, i) VALUES(1,2,3), (1,2,3), ... , (1,2,3)

批大小正好是 1000。我插入了近100批。我使用秒表检查了时间,发现了插入时间:

min[38ms], avg[50ms], max[190ms] per batch

我很高兴,但我想让我的代码更好。

在那之后,我尝试使用jdbcTemplate.batchUpdate,如下所示:

    jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
        @Override
        public void setValues(PreparedStatement ps, int i) throws SQLException {
                       // ...
        }
        @Override
        public int getBatchSize() {
            return 1000;
        }
    });

sql 看起来像

INSERT INTO TABLE(x, y, i) VALUES(1,2,3);

我很失望!jdbcTemplate 以分离的方式批量执行 1000 行的每个插入。我盯着mysql_log,发现那里有一千个插入物。我使用秒表检查了时间,发现了插入时间:

最小[900毫秒],平均[1100毫秒],最大[2000毫秒]每批次

那么,任何人都可以向我解释一下,为什么jdbcTemplate在这种方法中做分离的插入?为什么方法的名称是 batchUpdate?或者可能是我以错误的方式使用此方法?


答案 1

JDBC 连接 URL 中的这些参数可以对批处理语句的速度产生重大影响---根据我的经验,它们可以加快速度:

?useServerPrepStmts=false&rewriteBatchedStatements=true

请参见: JDBC 间歇刀片性能


答案 2

我发现在调用中设置argTypes数组有一个重大改进

在我的例子中,使用Spring 4.1.4和Oracle 12c,插入5000行和35个字段:

jdbcTemplate.batchUpdate(insert, parameters); // Take 7 seconds

jdbcTemplate.batchUpdate(insert, parameters, argTypes); // Take 0.08 seconds!!!

argTypes 参数是一个 int 数组,您可以按如下方式设置每个字段:

int[] argTypes = new int[35];
argTypes[0] = Types.VARCHAR;
argTypes[1] = Types.VARCHAR;
argTypes[2] = Types.VARCHAR;
argTypes[3] = Types.DECIMAL;
argTypes[4] = Types.TIMESTAMP;
.....

我调试了 org\springframework\jdbc\core\JdbcTemplate.java 发现大部分时间都花在了尝试了解每个字段的性质上,而这是为每条记录制作的。

希望这有帮助!


推荐