分布式数据库插入速度很慢

Distributed database insertion speed is very slow

@Test
public void transaction() throws Exception {
    Connection conn = null;
    PreparedStatement ps = null;
    try {
        String sql = "insert into `1` values(?, ?, ?, ?)";
        conn = JDBCUtils.getConnection();
        ps = conn.prepareStatement(sql);
        conn.setAutoCommit(false);
        for(int i = 1; i <= 10000; i++){
            ps.setObject(1, i);
            ps.setObject(2, 10.12345678);
            ps.setObject(3, "num_" + i);
            ps.setObject(4, "2021-12-24 19:00:00");
            ps.addBatch();
        }
        ps.executeBatch();
        ps.clearBatch();
        conn.commit();
    } catch (Exception e) {
        conn.rollback();
        e.printStackTrace();
    }finally {
        JDBCUtils.closeResources(conn, ps);
    }
}

当 setAutoCommit = true 时,本地 MySQL 和分布式 MySQL 插入速度非常慢。

当我将事务设置为手动提交时,就像上面的代码一样,本地MySQL速度提高了很多,但是分布式MySQL的插入速度仍然很慢。

我还需要设置其他参数吗?

设置参数可能无济于事(很多)。

速度慢有几个原因:

  1. autocommit=true 中,您将提交每个插入语句。这意味着每个新行都必须在数据库服务器 returns 响应客户端之前写入磁盘。

  2. 对于 autocommit=false,每个 insert 语句仍然存在客户端 -> 服务器 -> 客户端往返。这些往返行程加起来会花费大量时间。

加快速度的一种方法是在每个插入语句中插入多行,但这很麻烦,因为您需要生成复杂的(多行)插入语句。

更好的方法是使用 JDBC 的批处理功能来减少往返次数。例如:

  PreparedStatement ps = c.prepareStatement("INSERT INTO employees VALUES (?, ?)");

  ps.setString(1, "John");
  ps.setString(2,"Doe");
  ps.addBatch();

  ps.clearParameters();
  ps.setString(1, "Dave");
  ps.setString(2,"Smith");
  ps.addBatch();

  ps.clearParameters();
  int[] results = ps.executeBatch();

(归因:以上代码由@Tusc 从this answer 复制而来)

如果仍然不够快,您应该使用 MySQL 的本地批量插入机制获得更好的性能;例如load data infile;见 High-speed inserts with MySQL


为了完整起见,我添加了@Wilson Hauck 的建议

"In your configuration [mysqld] section, innodb_change_buffer_max_size=50 # from 25 (percent) for improved INSERT rate per second. SHOW FULL PROCESSLIST; to monitor when the instance has completed adjustment, then do your inserts and put it back to 25 percent for typical processing speed."

这可能会增加插入率,具体取决于您的 table 及其索引,以及您插入行的顺序。

但不利的一面是,您可以通过其他方式实现相同的加速(或更多!);例如

  • 通过对输入进行排序,以便按索引顺序插入行,或者
  • 删除索引,插入记录,然后重新创建索引。

您可以阅读更改缓冲区 here 并做出自己的判断。