prepareStatement.setString занимает более 5 секунд дольше, чем параметры жесткого кодирования - PullRequest
0 голосов
/ 10 октября 2011

Я подключаюсь к базе данных Microsoft sql server через java jdbc и у меня очень странная проблема.Всякий раз, когда я использую параметры заполнителя (?) В своем запросе в предложении where, а затем выполняю метод prepareStatement.setString (..), мой простой запрос выполняется в диапазоне от 4800 до 5800 миллисекунд.Когда я жестко кодирую предложение where внутри самого запроса, выполнение занимает от 1 до 36 миллисекунд.Это не имеет смысла для меня, потому что я думал, что использование заполнителей должно быть быстрее ...

В таблице действительно много строк (8 миллионов или около того), однако параметры, которые я передаюэто всего лишь несколько символов, я передаю только 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()

}

Вывод: run: take: 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 ПОСТРОИТЬ УСПЕШНО (общее время: 2 секунды)

1 Ответ

2 голосов
/ 10 октября 2011

Вообще говоря, выполнение полностью закодированного оператора будет быстрее, чем эквивалентный параметризованный оператор. Причина этого связана с планированием выполнения базы данных. Когда вы предоставляете всю информацию с самого начала, база данных может выполнять оптимизацию и выбирать более короткие пути, соответствующие точным данным, которые вы предоставили. При параметризации оператора он может выполнять только те оптимизации, которые будут полезны для любого значения, которое может быть вставлено.

Параметризованные операторы могут быть полезны, когда вам нужно выполнить много похожих запросов и вы хотите избежать ненужной подготовки каждого оператора каждый раз, но для одного запроса к большому набору данных (как в вашем случае использования) жестко закодированный запрос будь лучше.

...