更新单个表的多行

我需要更新具有超过60k行的表的每一行。 目前我这样做 –

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

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

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

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

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

也就是说,您应该开始使用预准备语句和批处理:

 public void updateRank(Map map){ Iterator> 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 pairs = (Map.Entry)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只传输一次,数据被收集并作为数据包发送(或至少更少的数据包)

此外:

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

您可以连接查询(将它们分隔开; )并仅发送100个查询批次。

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

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

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

参考