[英]JDBC Delete Works Slow
我在sql server上的JDBC Delete語句中遇到性能問題。 表Config包含大約700萬行,表詳細信息:
列:
索引: TERMINAL_ID和ATTRIBUTE上的群集唯一索引
代碼看起來像這樣,其中屬性長度為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時,問題就消失了。
我找到了問題並解決了它。 問題出在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.