Jdbc preparedStatement.setString比硬编码参数长5秒以上

Jdbc preparedStatement.setString比硬编码参数长5秒以上,jdbc,prepared-statement,Jdbc,Prepared Statement,我通过JavaJDBC连接到MicrosoftSQLServer数据库,遇到了一个非常奇怪的问题。每当我在where子句中的查询中使用占位符参数(?),然后执行preparedStatement.setString(..)方法时,我的简单查询运行时间从4800毫秒到5800毫秒不等。当我在查询本身内部硬编码where子句时,运行需要1到36毫秒。这对我来说没有意义,因为我认为使用占位符应该更快 这个表确实有很多行(800万左右),但是我传入的参数只有几个字符,我只传入2个参数,语句总是返回1(或

我通过JavaJDBC连接到MicrosoftSQLServer数据库,遇到了一个非常奇怪的问题。每当我在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秒)

一般来说,运行完全硬编码的语句将比等效的参数化语句快。其原因与数据库的执行计划有关。当您从一开始就提供所有信息时,数据库可以执行优化,并针对您提供的确切数据选择更短的路径。当您参数化语句时,它只能执行那些对可能插入的任何值都有帮助的优化


当您需要运行许多类似的查询并希望避免每次准备语句的开销时,参数化语句可能会很有用,但对于大型数据集上的单个查询(如在您的用例中),硬编码查询会更好

在这种情况下,您建议如何缩短时间并仍然使用参数化查询?我不愿意使用硬编码查询,因为where子句中的内容来自用户输入,而不使用参数,这使得应用程序更容易受到sql注入的影响。5-6秒对于这样一个小的查询来说是一个巨大的时间。甚至没有任何连接。在java方面还有什么可以提高性能的方法吗?一种可能的解决方案是使用硬编码查询,前提是您可以轻松地验证输入是否安全(例如,仅使用字母数字和空格),并保留参数化查询以供更可疑的输入使用。当然,只有当你期望的“正常”输入很容易识别时,这才有意义。