批量插入需要花费很长时间

时间:2020-10-26 21:18:02

标签: java mysql

我们很难一次插入很多行。
我们正在将项目运行到localhost MySQL数据库的计算机上,以确保服务器的性能不成问题。
这么长的插入时间有什么关系吗?

代码中的注释准确地说明了导致我们出现问题的那一行

public <T> void batchExecute(String query, BatchArgSetter<T> batchArgSetter) {
    Connection con = this.getConnection();
    PreparedStatement statement = null;
    int i = 0;
    try {
        con.setAutoCommit(false);
        statement = con.prepareStatement(query);
        while (batchArgSetter.hasNext()) {
         // This code to set args and add batch is instant. About 0.05 ms per per 1000.
            setArgs(statement, batchArgSetter.getArgs(batchArgSetter.next()));
            statement.addBatch();
            i++;
            if (i % 1000 == 0 || i == batchArgSetter.getSize()) {

             // However, this line takes forever.
             // About 30 seconds per batch. A test with 9600 entries took a total time of 5min 42sec
             // We tried testing a collection of 100k+ entries, which we stopped after id had run 10min +
                statement.executeBatch();
                con.commit();
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        closeAll(statement, null, con);
    }
}

SQL类的设置

public class SqlConnection {
    private String username;
    private String password;
    private String url;
    private HikariConfig config = new HikariConfig();
    private HikariDataSource ds;

    public SqlConnection(Setting.PersistenceSetting setting) {
        this.username = setting.getUsername();
        this.password = setting.getPassword();
        this.url = "jdbc:mysql://" + setting.getUrl() + ":" + setting.getPort() + "/" + setting.getDatabase() + "?serverTimezone=UTC";
        setup(setting.getPoolSize());
    }


    private void setup(int poolSize) {
        config.setJdbcUrl(url);
        config.setUsername(username);
        config.setPassword(password);
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.setMaximumPoolSize(poolSize);
        config.setLeakDetectionThreshold(2000);
        config.setAutoCommit(true);
        ds = new HikariDataSource(config);
    }

我调用SQL方法的代码

    private void insertMembers(List<Member> members) {
        sql.batchExecute("INSERT INTO user VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE username = ?, discriminator = ?, avatar = ?;", new BatchArgSetter<Member>(members) {
            @Override
            public Object[] getArgs(Member m) {
                return new Object[]{
                        m.getIdLong(),
                        m.getUser().getName(),
                        m.getUser().getDiscriminator(),
                        m.getUser().getEffectiveAvatarUrl(),

                        m.getUser().getName(),
                        m.getUser().getDiscriminator(),
                        m.getUser().getEffectiveAvatarUrl()
                };
            }
        });
        sql.batchExecute("INSERT INTO guild_member VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE nickname=?", new BatchArgSetter<Member>(members) {
            @Override
            public Object[] getArgs(Member member) {
                return new Object[]{
                        member.getIdLong(),
                        member.getGuild().getIdLong(),
                        member.getNickname(),
                        member.getNickname()
                };
            }
        });
    }

0 个答案:

没有答案