更新单个表的多行

时间:2013-12-03 15:07:27

标签: java mysql

我需要更新行数超过6万的表的每一行。 目前我这样做 -

public void updateRank(Map<Integer,Double> map){
        Iterator<Entry<Integer, Double>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Integer,Double> pairs = (Map.Entry<Integer,Double>)it.next();
            String query = "update profile set rank = "+ pairs.getValue()+ " where profileId = "+pairs.getKey();
            DBUtil.update(query);
            it.remove();
        }       
}

仅此方法需要大约20分钟才能完成,每行(60k)命中数据库就是我认为的原因。(虽然我使用dbcp进行连接池,最多有50个活动连接)

如果我能够使用单个数据库命中更新行,那就太好了。那可能吗 ?怎么样?

或者其他任何改善时间的方法?

3 个答案:

答案 0 :(得分:11)

如果每一行都应该得到一个不能从数据库中的现有数据中获得的不同值,那么您无法做很多事情来优化整体复杂性。所以不要期待太多的奇迹。

那就是说,你应该开始使用预备语句和批处理:

public void updateRank(Map<Integer,Double> map){
    Iterator<Entry<Integer, Double>> it = map.entrySet().iterator();
    String query = "";
    int i = 0;

    Connection connection = getConnection(); // get the DB connection from somewhere
    PreparedStatement stmt = connection.prepareStatement("update profile set rank = ? where profileId = ?");

    while (it.hasNext()) {
        Map.Entry<Integer,Double> pairs = (Map.Entry<Integer,Double>)it.next();
        stmt.setInt(1, pairs.getValue());
        stmt.setDouble(2, pairs.getKey());
        stmt.addBatch(); // this will just collect the data values
        it.remove();
    }       
    stmt.executeBatch(); // this will actually execute the updates all in one
}

这是做什么的:

  1. 预准备语句导致SQL解析器仅解析SQL一次
  2. 批处理最小化客户端 - 服务器 - 往返,以便每次更新都不会有一个
  3. 客户端和服务器之间的通信被最小化,因为SQL只传输一次,数据被收集并作为数据包发送(或至少更少的数据包)
  4. 另外:

    • 请检查数据库列profileId是否正在使用索引,以便查找相应的行足够快
    • 您可以检查您的连接是否设置为自动提交。如果是这样,请尝试禁用自动提交并在更新所有行后显式提交事务。这样,单个更新操作也可以更快。

答案 1 :(得分:2)

您可以连接查询(用;分隔)并仅发送100个查询批量。

public void updateRank(Map<Integer,Double> map){
        Iterator<Entry<Integer, Double>> it = map.entrySet().iterator();
        String queries = "";
        int i = 0;
        while (it.hasNext()) {
            Map.Entry<Integer,Double> pairs = (Map.Entry<Integer,Double>)it.next();
            queries += "update profile set rank = "+ pairs.getValue()+ " where profileId = "+pairs.getKey() + ";";
            it.remove();
            if(i++ % 100 == 99){
               DBUtil.update(queries);
               queries = "";
            }
        }       
}

答案 2 :(得分:2)

现在您独立执行每个查询会导致巨大的连接开销(即使使用连接池)。而是使用批处理机制一起执行多个查询。

使用JDBC(DBCP显然正在使用)和准备好的语句,您可以使用addBatch()executeBatch()轻松完成此操作。我最近不得不自己做这件事,批量大约1000个查询是最快的。虽然在你的情况下这可能完全不同。

<强>参考