preparedStatement.setString比硬编码参数长5秒多

时间:2011-10-10 18:11:52

标签: jdbc prepared-statement

我通过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秒)

1 个答案:

答案 0 :(得分:2)

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

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