Любой способ * не * использовать подготовленные операторы на стороне сервера в Postgresql? - PullRequest
4 голосов
/ 19 июля 2011

В (скажем) Python я могу выдать:

psycopg2.connect(...).cursor().execute("select * from account where id='00100000006ONCrAAO'")

, что на сервере приводит к следующим записям в журнале:

2011-07-18 18:56:08 PDT LOG:  duration: 6.112 ms  statement: select * from account where id='00100000006ONCrAAO'

Однако в Java выдается:

conn.createStatement().executeQuery("select * from account where id = '00100000006ONCrAAO'");

приводит к:

2011-07-18 18:44:59 PDT LOG:  duration: 4.353 ms  parse <unnamed>: select * from account where id = '00100000006ONCrAAO'
2011-07-18 18:44:59 PDT LOG:  duration: 0.230 ms  bind <unnamed>: select * from account where id = '00100000006ONCrAAO'
2011-07-18 18:44:59 PDT LOG:  duration: 0.246 ms  execute <unnamed>: select * from account where id = '00100000006ONCrAAO'

В некоторых результатах поиска драйвер PG JDBC всегда использует подготовленные операторы: http://postgresql.1045698.n5.nabble.com/JDBC-prepared-statements-amp-server-side-prepared-statements-td1919506.html

ЕстьЛюбой способ обойти сервер подготовленные заявления?Если это имеет значение, я спрашиваю относительно PG 8.4 и 9.0.

Ответы [ 4 ]

2 голосов
/ 17 марта 2016

Вам нужно добавить параметр

prepareThreshold=0

к URL-адресу подключения драйвера JDBC примерно так:

jdbc:postgresql://db.address/dbName?prepareThreshold=0

см. Также https://github.com/pgjdbc/pgjdbc/issues/130, это мне очень помоглорешить странное поведение водителя

2 голосов
/ 19 июля 2011

Документация драйвера JDBC содержит подробные сведения о том, когда и как используются подготовленные операторы на стороне сервера.

В любом случае, вывод журнала, который вы показываете, не указывает на проблему, потому что любой запрос будет проанализирован, привязан и выполнен. Драйвер JDBC просто выбирает выполнение этих шагов как отдельных шагов протокола, а не как один шаг, как это делает драйвер Python. (Я полагаю, что вы могли бы поспорить о затратах в сети.) Проблема, которую большинство людей беспокоит в отношении подготовленных операторов, заключается в том, что параметры заменяются после планирования, но это не то, что здесь происходит, поскольку <unnamed> подготовленные операторы планируются после шаг связывания (в отличие от именованных подготовленных операторов, которые планируются после шага разбора). Вы можете прочитать эти детали в документации по протоколу .

1 голос
/ 20 июля 2011

Получил ответ из списка рассылки драйвера JDBC Postgresql:

Вы можете использовать протокол v2 (который вставляет значения параметров в виде текста, а не отправляет их вне строки), но вы потеряетеразличные другие функциональные возможности драйвера, которые зависят от протокола v3.

Использование протокола V2 заставило драйвер использовать простой протокол запросов вместо расширенного протокола запросов и вернул производительность на уровни.мы видели в Python.

1 голос
/ 19 июля 2011

Во-первых, под капотом каждые дБ используются подготовленные заявления, даже если они созданы на лету и немедленно выброшены.

Во-вторых, вам не следует бояться готовых высказываний. Они предлагают огромный прирост производительности: после создания их можно повторно использовать с различными параметрами, но все разбор, проверка авторизации пользователя, план запроса и оптимизация рассчитываются один раз и сохраняются с подготовленным оператором.

Если вы собираетесь выполнять один и тот же sql снова и снова, создайте подготовленный оператор, сохраните ссылку на него и используйте его повторно - предоставляя разные параметры для каждого вызова.

Вот пример кода, чтобы дать вам представление о том, как его использовать:

private PreparedStatement preparedStatement;

public ResultSet getAccount(String id) throws SQLException {
    // Do this once
    if (preparedStatement == null)
        preparedStatement = conn.prepareStatement("select * from account where id = ?");

    // Do this many times
    preparedStatement.setString(1, id);
    return preparedStatement.executeQuery();
}

public static void main(String[] args) throws Exception {
    ResultSet rs = new MyClass().getAccount("00100000006ONCrAAO");
}
...