2013-10-04 68 views
1

在我的应用程序中,我有一个包含大约200K条记录的表,我需要在数据库中进行更新。我认为更快的方法是删除数据库中的所有匹配记录并插入它们,而不是检查每条记录是否存在数据库中的匹配记录,然后插入或更新。我正在使用Spring JDBC框架。 要删除,我用的JdbcTemplate BATCHUPDATE方法有ParameterizedPreparedStatementSetter沿和插入我使用SimplJdbcInsert。 插入工作正常,但是,批量删除性能非常缓慢。 我不太确定采取什么其他方法来删除数据库中的记录并插入它们。任何建议都会非常有帮助。我使用SQL Server 2008 R2的Spring JDBC - 批量删除和插入

ParameterizedPreparedStatementSetter<Order> vSetter = 
      new ParameterizedPreparedStatementSetter<Order>() { 
       @Override 
       public void setValues(PreparedStatement ps, 
         Order order) throws SQLException { 
        ps.setInt(1, order.getOrderNum()); 
       } 
    }; 

getJdbcTemplate().batchUpdate("DELETE FROM Order WHERE OrderNum = ?", 
      aDemandOrders, 
      50000, 
      vSetter); 
+1

我建议使用['MERGE'](http://msdn.microsoft.com/en-us/library/bb510625.aspx)而不是删除然后插入。 –

+0

我最终做了更新并基于更新计数执行了插入操作。帮助提高了性能 – user320587

回答

1

的原因性能下降的是,DB将接收一批语句,而是由一个仍执行它们之一。

一种替代方法是使用in()子句和手动批量的语句,以允许DB与每个批量的执行一个语句。

为了仍然得到查询缓存的好处,但是你不能简单地将所有在一个单一的in()条款,应分批予以适当。

private static final int MIN = 1; 
private static final int SML = 4; 
private static final int MED = 11; 
private static final int MAX = 51; 
private static final String DEL_ORDERS_QRY 
    = "DELETE FROM Order WHERE OrderNum in (:orders)"; 

public void deleteOrders(Collection<Integer> origIds) { 
    int done = getJdbcTemplate().execute((Connection con) -> { 
     // Reuse this query, `:orders` is a placeholder for the in-clause. 

     LinkedList<Integer> ids = new LinkedList<>(origIds); 
     int remainder = ids.size(); 
     int updated = 0; 

     while (remainder > 0) { 
      // identify the batch size for this execution. 
      int batchSize; 
      if (remainder >= MAX) { 
       batchSize = MAX; 
      } else if (remainder >= MED) { 
       batchSize = MED; 
      } else if (remainder >= SML) { 
       batchSize = SML; 
      } else { 
       batchSize = MIN; 
      } 
      remainder -= batchSize; 

      // Build the in-clause parameters. 
      StringBuilder inClause = new StringBuilder(batchSize * 2); 
      for (int i = 0; i < batchSize; i++) { 
       if (i > 0) { 
        inClause.append(','); 
       } 
       inClause.append('?'); 
      } 

      try (PreparedStatement ps = con.prepareStatement(
        DEL_ORDERS_QRY.replace(":orders", inClause.toString()))) { 
       for (int i = 0; i < batchSize; i++) { 
        ps.setInt(i + 1, ids.pop()); 
       } 
       updated += ps.executeUpdate(); 
      } catch (SQLException ex) { 
       log.error("Couldn't execute batch", ex); 
       throw new RuntimeException(ex.getMessage(), ex); 
      } 
     } 
     return updated; 
    }); 
}