我通過java jdbc連接到Microsoft sql server數據庫並出現了一個非常奇怪的問題。每當我在where子句的查詢中使用佔位符參數(?),然後執行preparedStatement.setString(..)方法時,我的簡單查詢需要4800到5800毫秒的任何時間才能運行。當我在查詢本身內部對where子句進行硬編碼時,運行需要1到36毫秒。這對我來說沒有意義,因爲我認爲使用佔位符應該更快......preparedStatement.setString比硬編碼參數長5秒以上
該表確實有很多行(800萬左右),但是我傳入的參數是隻有幾個字符,我只傳入2個參數,該語句總是返回1(或0)行,它返回的數據並不是很大。桌上的索引不起作用。爲什麼這麼大的時差? 5-6秒對於這樣的查詢是非常長的時間。 where子句中的兩列都是string-type(varchar(20)),所以在數據庫端沒有隱式類型轉換(我知道)。
我已經嘗試過不同版本的sqljdbc4.jar驅動程序,但它的功能相同。
package testdbconnection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws SQLException
{
Connection con = getConnection();
PreparedStatement statement = con.prepareStatement("select col1 from tableName where username = ? and password = ?");
statement.setString(1, "UName");
statement.setString(2, "PWord");
long start = System.currentTimeMillis();
ResultSet rs = statement.executeQuery();
long stop = System.currentTimeMillis();
System.out.println("took: " + (stop - start));
rs.close();
con.close();
}// end main
private static Connection getConnection()
{
Connection connection = null;
try {
// Load the JDBC driver
String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
Class.forName(driverName);
// Create a connection to the database
String url = "jdbc:sqlserver://DBSERVERNAME;databaseName=DBNAME;";
String username = "dbUname";
String password = "dbPword";
connection = DriverManager.getConnection(url, username, password);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (SQLException e)
{
e.printStackTrace();
}
return connection;
}// end getConnection()
}
輸出: 運行: 了:4891 BUILD SUCCESSFUL(總時間:5秒)
現在,如果我這樣做:
package testdbconnection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws SQLException
{
Connection con = getConnection();
PreparedStatement statement = con.prepareStatement("select col1 from tableName where username = 'UName' and password = 'PWord'");
long start = System.currentTimeMillis();
ResultSet rs = statement.executeQuery();
long stop = System.currentTimeMillis();
System.out.println("took: " + (stop - start));
rs.close();
con.close();
}// end main
private static Connection getConnection()
{
Connection connection = null;
try {
// Load the JDBC driver
String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
Class.forName(driverName);
// Create a connection to the database
String url = "jdbc:sqlserver://DBSERVERNAME;databaseName=DBNAME;";
String username = "dbUname";
String password = "dbPword";
connection = DriverManager.getConnection(url, username, password);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (SQLException e)
{
e.printStackTrace();
}
return connection;
}// end getConnection()
}
輸出: 運行: 了:32 BUILD SUCCESSFUL(總時間:2秒)
在這種情況下,你會建議什麼來縮短時間並仍然使用參數化查詢?我不願意使用硬編碼的查詢,因爲where子句中的東西來自用戶輸入,而不使用參數會使應用程序更容易受到sql注入的影響。 5-6秒對於這樣一個小的查詢來說是一個很大的時間。甚至沒有任何連接。有沒有其他的事情可以在java端完成以提高性能? – Creature
一個可能的解決方案是使用硬編碼查詢,如果您可以輕鬆驗證輸入是否安全(僅限字母數字和空白),並保留參數化查詢以用於更多可疑輸入。這隻有在你預期的「正常」輸入很容易識別和確定時纔有意義。 – nonVirtualThunk
是的,看起來我必須這樣做。謝謝! – Creature