簡體   English   中英

JDBC刪除工作緩慢

[英]JDBC Delete Works Slow

我在sql server上的JDBC Delete語句中遇到性能問題。 表Config包含大約700萬行,表詳細信息:

列:

  1. TERMINAL_ID(varchar(50))
  2. ATTRIBUTE(VARCHAR(50))
  3. VALUE(nvarchar(1000))

索引: TERMINAL_IDATTRIBUTE上的群集唯一索引

代碼看起來像這樣,其中屬性長度為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次時,只需幾秒鍾即可刪除。 執行計划如下所示: 在此輸入圖像描述 當行數很小時,問題就會消失。

當我使用createStatement而不是prepareStatement時,問題就出現了。

任何的想法 ?

嘗試使用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 

我最近遇到了類似的問題,通過JDBC的DELETE性能很慢。

操作很簡單:DELETE FROM t WHERE id =?

id字段是主鍵。

但是,我在perfmon中注意到刪除操作正在觸發完整掃描。

據我所知,潛在的問題是該列是varchar而不是nvarchar,並且JDBC驅動程序正在重寫delete以在查詢期間執行id的隱式轉換,而不是轉換文字值。

此轉換阻止查詢使用索引。

當我將列切換為使用nvarchar時,問題就消失了。

使用SQL Server JDBC驅動程序時的字符數據類型轉換

我找到了問題並解決了它。 問題出在prepareStatement.setString()方法中,它生成了不同的查詢,執行計划也不同。

我打開了運行查詢的SQL Server Activity Monitor

DELETE FROM Config WHERE TERMINAL_ID = @ P0 AND ATTRIBUTE = @ P1
在此輸入圖像描述

所以我右鍵單擊查詢並打開執行計划,如下所示:

在此輸入圖像描述

正如我猜測SQL Server為每一行調用CONVERT_IMPLICIT函數並在聚簇索引中進行掃描。 這個軟件是第三方,所以我不得不將列更改為nvarchar,問題已經消失。

嘗試禁用此連接的自動提交,然后在完成所有刪除語句后手動提交:

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教程

將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();
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM