JDBC删除工作缓慢

时间:2015-06-08 11:50:37

标签: java sql-server jdbc

我在sql server上的 JDBC 删除语句中遇到性能问题。 表Config包含大约700万行,表格详细信息:

列:

  1. TERMINAL_ID(varchar(50))
  2. ATTRIBUTE(VARCHAR(50))
  3. VALUE(nvarchar(1000))
  4. 索引: TERMINAL_ID 属性

    上的群集唯一索引

    代码看起来像这样,其中属性长度为1500,此程序需要大约1小时才能完成,这对于删除来说非常慢:

         PreparedStatement statement = null;
         String sql = "DELETE FROM Config WHERE TERMINAL_ID = ? AND ATTRIBUTE = ?");
         for (String attribute : attributes) {
                if (statement == null) {
                    statement = connection.prepareStatement(sqlDelete);
                }
                statement.setString(1, terminalId);
                statement.setString(2, attribute);
                statement.executeUpdate();
          }
    

    当我在Management Studio中运行此查询1500次时,只需几秒钟即可删除。执行计划如下所示: enter image description here 当行数很小时,问题就会消失。

    当我使用createStatement而不是prepareStatement时,问题就会消失。

    任何想法?

4 个答案:

答案 0 :(得分:3)

尝试使用preparedStatement.addBatch()这可能会提高效果,

 PreparedStatement statement = null;
 String sql = "DELETE FROM Config WHERE TERMINAL_ID = ? AND ATTRIBUTE = ?");
     for (String attribute : attributes) {
            if (statement == null) {
                statement = connection.prepareStatement(sqlDelete);
            }
            statement.setString(1, terminalId);
            statement.setString(2, attribute);
            statement.addBatch();
      }
statement.executeBatch();
//commit 

答案 1 :(得分:1)

我找到了问题并解决了它。问题出在方法 preparedStatement.setString(),它生成了不同的查询,执行计划也不同。

我打开了运行查询的SQL Server活动监视器

DELETE FROM Config WHERE TERMINAL_ID = @ P0 AND ATTRIBUTE = @ P1
enter image description here

所以我右键单击查询并打开执行计划,如下所示:

enter image description here

正如我猜测SQL Server为每一行调用CONVERT_IMPLICIT函数并在聚簇索引中进行扫描。这个软件是第三方,因此我不得不将列更改为nvarchar并且问题已经消失。

答案 2 :(得分:0)

尝试为此连接禁用自动提交,然后在完成所有删除语句后手动提交:

PreparedStatement statement = null;
String sql = "DELETE FROM Config WHERE TERMINAL_ID = ? AND ATTRIBUTE = ?");
try {
    connection.setAutoCommit(false);
    for (String attribute : attributes) {
        if (statement == null) {
            statement = connection.prepareStatement(sqlDelete);
        }
        statement.setString(1, terminalId);
        statement.setString(2, attribute);
        statement.executeUpdate();
    }
    connection.commit();
} finally {
    connection.setAutoCommit(true);
}

为简洁起见,我省略了异常处理。有关更详细的示例,请参阅JDBC tutorial

答案 3 :(得分:0)

将prepareStatement移到循环外部。

 String sql = "DELETE FROM Config WHERE TERMINAL_ID = ? AND ATTRIBUTE = ?");
 PreparedStatement statement = connection.prepareStatement(sqlDelete);

 for (String attribute : attributes) {
        statement.setString(1, terminalId);
        statement.setString(2, attribute);
        statement.executeUpdate();
  }