更新单个表的多行
我需要更新具有超过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 }
这是做什么的:
- 准备好的语句使SQL解析器只解析SQL一次
- 批处理最小化客户端 – 服务器 – 往返,以便每次更新都不会
- 客户端和服务器之间的通信被最小化,因为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个查询是最快的。 虽然在您的情况下这可能完全不同。
参考