JDBC批量插入性能

时间:2010-06-07 21:17:47

标签: mysql performance jdbc batch-file

我需要在mysql数据库中插入几亿条记录。我一次批量插入100万。请参阅下面的代码。这看起来很慢。有没有办法优化它?

try {
        // Disable auto-commit
        connection.setAutoCommit(false);

        // Create a prepared statement
        String sql = "INSERT INTO mytable (xxx), VALUES(?)";
        PreparedStatement pstmt = connection.prepareStatement(sql);

        Object[] vals=set.toArray();
        for (int i=0; i<vals.length; i++) {
            pstmt.setString(1, vals[i].toString());
            pstmt.addBatch();
        }

        // Execute the batch
        int [] updateCounts = pstmt.executeBatch();
        System.out.append("inserted "+updateCounts.length);

6 个答案:

答案 0 :(得分:159)

我遇到了与mysql类似的性能问题,并通过在连接URL中设置 useServerPrepStmts rewriteBatchedStatements 属性来解决这个问题。

Connection c = DriverManager.getConnection("jdbc:mysql://host:3306/db?useServerPrepStmts=false&rewriteBatchedStatements=true", "username", "password");

答案 1 :(得分:53)

我想扩展Bertil的答案,因为我一直在试验连接网址参数。

rewriteBatchedStatements=true是重要参数。默认情况下,useServerPrepStmts已经为假,即使将其更改为true,在批量插入效果方面也没有太大差异。

现在我想是时候写rewriteBatchedStatements=true如何显着提高性能。它由rewriting of prepared statements for INSERT into multi-value inserts when executeBatch()Source)完成。这意味着每次调用n时,不要将以下executeBatch() INSERT语句发送到mysql服务器:

INSERT INTO X VALUES (A1,B1,C1)
INSERT INTO X VALUES (A2,B2,C2)
...
INSERT INTO X VALUES (An,Bn,Cn)

它会发送一个INSERT语句:

INSERT INTO X VALUES (A1,B1,C1),(A2,B2,C2),...,(An,Bn,Cn)

您可以通过切换mysql日志记录(SET global general_log = 1)来观察它,这将记录发送到mysql服务器的每个语句的文件。

答案 2 :(得分:11)

您可以使用一个insert语句插入多行,一次执行几千行可以大大加快速度,也就是说,而不是例如3. INSERT INTO tbl_name (a,b,c) VALUES(1,2,3);形式的3个插入,你做INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(1,2,3),(1,2,3);(它可能是JDBC .addBatch()现在做类似的优化 - 尽管mysql addBatch曾经是非常优化的,无论如何只发出个别查询 - 我不知道最近的司机是否仍然如此)

如果您确实需要速度,请使用逗号分隔文件LOAD DATA INFILE加载数据,我们可以获得大约7-8倍的速度,而不是数千万次插入。

答案 3 :(得分:4)

如果:

  1. 这是一个新表,或者要插入的数量大于已插入的数据
  2. 表上有索引
  3. 在插入
  4. 期间,您不需要对表格进行其他访问

    然后ALTER TABLE tbl_name DISABLE KEYS可以大大提高插入速度。完成后,运行ALTER TABLE tbl_name ENABLE KEYS开始构建索引,这可能需要一段时间,但不会像为每个插入操作那样长。

答案 4 :(得分:1)

您可以尝试使用DDBulkLoad对象。

// Get a DDBulkLoad object
DDBulkLoad bulkLoad = DDBulkLoadFactory.getInstance(connection);
bulkLoad.setTableName(“mytable”);
bulkLoad.load(“data.csv”);

答案 5 :(得分:1)

try {
        // Disable auto-commit
        connection.setAutoCommit(false);
        int maxInsertBatch = 10000;     
        // Create a prepared statement
        String sql = "INSERT INTO mytable (xxx), VALUES(?)";
        PreparedStatement pstmt = connection.prepareStatement(sql);

        Object[] vals=set.toArray();
        int count = 1;
        for (int i=0; i<vals.length; i++) {
            pstmt.setString(1, vals[i].toString());
            pstmt.addBatch();
            if(count%maxInsertBatch == 0){
                 pstmt.executeBatch();
            }
            count++;
        }

        // Execute the batch
        pstmt.executeBatch();
        System.out.append("inserted "+count);