让ExecuteBatch更快地执行

时间:2012-02-16 21:28:31

标签: java sql jdbc sybase

我尝试从sybase服务器读取表,处理行,并将结果输出到另一个表。 (下面是我的代码)

代码可以非常快速地检索表格并且处理速度相同(在30秒内发送到它的部分)。但是当我运行执行批处理时,它会在那里停留20分钟才能完成(fyi,我有一张表,我正在测试8400行)。

有更有效的方法吗?我能够接受或发送查询(我可以创建一个新表,更新表等) - 我只是不知道为什么这么慢(我'确保数据< 1 MB并且我确定它不会使SQL服务器在20分钟内解析8400行。有什么想法吗?

注意:这对我来说真的很糟糕的原因是我必须解析一个1.2 MM行的表(这个表我现在正在使用的是一个8400行的测试表)

    Connection conn = DriverManager.getConnection(conString, user, pass);


    String sql = "SELECT id,dateid,attr from user.fromtable";
    Statement st = conn.createStatement();
    ResultSet rs = st.executeQuery(sql);

    String sqlOut = "INSERT INTO user.mytabletest (id,attr,date,estEndtime) values (?,?,?,?)";
    PreparedStatement ps = conn.prepareStatement(sqlOut);

    int i=1;

    while(rs.next())
    {
        int date = rs.getInt("dateid");
        String attr = rs.getString("attr");
        String id = rs.getString("id");

        Time tt = getTime(date,attr);
        Timestamp ts = new Timestamp(tt.getTime());

        ps.setString(1, id);
        ps.setString(2, attr);
        ps.setInt(3, date);
        ps.setTimestamp(4, ts);
        ps.addBatch();

        if(i % 10000 == 0)
        {
            System.out.println(i);
            ps.executeBatch();
            conn.commit();
            ps.clearBatch();                
        }

        i++;
    }
    System.out.println("sending "+(new Date()));
    int[] results = ps.executeBatch();
    System.out.println("committing "+(new Date()));
    conn.commit();
    System.out.println("done "+(new Date()));

4 个答案:

答案 0 :(得分:8)

要有效地使用批次,您应该关闭AutoCommit选项并在执行批处理后将其打开(或者使用connection.commit()方法)

connection.setAutoCommit(false);
while(rs.next())
    {
     .....
     ps.addBatch();     
    }
int[] results = ps.executeBatch();
connection.setAutoCommit(true);

答案 1 :(得分:5)

我遇到了同样的问题,终于弄明白了,虽然我也无法在任何地方找到正确的解释。

答案是,对于简单的无条件插入.executeBatch()不应该使用。批处理模式正在做的是使许多单独的“插入表x ...”语句,这就是它运行缓慢的原因。但是,如果insert语句更复杂,可能的条件会不同地影响每一行,那么它可能需要单独的insert语句,批处理执行实际上是有用的。

一个有效的例子,尝试以下创建单个insert语句作为PreparedStatement(但与Statement对象需要相同的概念),并解决运行缓慢的问题:

public boolean addSetOfRecords(String tableName, Set<MyObject> objects) {
    StringBuffer sql = new StringBuffer("INSERT INTO " + tableName + " VALUES (?,?,?,?)");
    for(int i=1;i<objects.size();i++) {
        sql.append(",(?,?,?,?)");
    }
    try {
        PreparedStatement p = db.getConnection().prepareStatement(sql.toString());
        int i = 1;
        for(MyObject obj : objects) {
            p.setString(i++, obj.getValue());
            p.setString(i++, obj.getType());
            p.setString(i++, obj.getId());
            p.setDate(i++, new Date(obj.getRecordDate().getTime()));
        }
        p.execute();
        p.close();
        return true;
    } catch (SQLException e) {
        e.printStackTrace();
        return false;
    }
}

答案 2 :(得分:3)

?rewriteBatchedStatements = true 添加到JDBC网址的末尾。它将为您带来严重的性能提升。请注意,这是特定于MySql的,不会对任何其他JDBC驱动程序产生任何影响。

例如: jdbc:mysql:// server:3306 / db_name?rewriteBatchedStatements = true

它使我的表现提高了15倍以上

答案 3 :(得分:0)

Progress DataDirect有一个商业解决方案,可以将JDBC批次转换为数据库的本机批量加载协议,从而显着提高性能。它非常受SQL Server欢迎,因为它不需要BCP。我受雇于该供应商并在how to bulk insert JDBC batches上写了一篇博客。