我通过java jdbc连接到Microsoft sql server数据库并且有一个非常奇怪的问题。每当我在where子句的查询中使用占位符参数(?)然后执行preparedStatement.setString(..)方法时,我的简单查询需要4800到5800毫秒才能运行。当我在查询本身内部对where子句进行硬编码时,运行需要1到36毫秒。这对我来说没有意义,因为我认为使用占位符应该更快......
该表确实有很多行(800万左右),但是我传入的参数只有几个字符,我只传入2个参数,该语句总是返回1(或0)行,它返回的数据并不大。表上的索引没有帮助。为什么这么大的时差呢? 5-6秒对于这样的查询来说真是太长时间了。 where子句中的两列都是字符串类型(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 建立成功(总时间: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 建立成功(总时间:2秒)
答案 0 :(得分:2)
一般来说,运行完全硬编码的语句会比等效的参数化语句更快。其原因与数据库的执行计划有关。当您从一开始就提供所有信息时,数据库可以执行优化并选择特定于您提供的确切数据的较短路径。参数化语句时,它只能执行那些对可能插入的任何值有帮助的优化。
当您需要运行许多类似的查询并且希望避免每次准备语句的开销时,参数化语句会很有用,但对于大型数据集上的单个查询(如在您的用例中),硬编码查询将会更好。