Any way to *not* use server-side prepared statements in Postgresql?

馋奶兔 提交于 2019-12-10 15:43:42

问题


In (say) Python, I can issue:

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

which on the server results in the following log entries:

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

However, in Java, issuing:

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

results in:

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'

Some searching shows that the PG JDBC driver always uses prepared statements: http://postgresql.1045698.n5.nabble.com/JDBC-prepared-statements-amp-server-side-prepared-statements-td1919506.html

Is there any way to circumvent server prepared statements? If it makes a difference, I'm asking regarding PG 8.4 and 9.0.


回答1:


The JDBC driver documentation contains the gory details of when and how server-side prepared statements are used.

Anyway, the log output you show isn't indicative of a problem, because any query will be parsed, bound, and executed. The JDBC driver just chooses to execute those steps as separate protocol steps rather than one step like the Python driver does. (I suppose you could argue network overhead, though.) The issue most people are concerned about with respect to prepared statements is that parameters are substituted after planning, but that's not what is happening here, because <unnamed> prepared statements are planned after the bind step (unlike named prepared statements, which are planned after the parse step). You can read up on those details in the protocol documentation.




回答2:


You need to add

prepareThreshold=0

parameter to the JDBC driver connection URL something like this:

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

see also https://github.com/pgjdbc/pgjdbc/issues/130 it helped me a lot to solve a strange behavior of the driver




回答3:


Firstly, under the hood, every db uses prepared statements, even if created on the fly and immediately thrown away.

Secondly, you shouldn't be afraid of prepared statements. They offer a huge performance boost: Once created they can be reused with different parameters, but all the parsing, user authorization checking, query plan and optimization is calculated once and stored with the prepared statement.

If you're going to be executing the same sql over and over, create a prepared statement, keep a reference to it, and reuse it - providing different parameters for each invocation.

Here's some sample code to give you an idea of how to use them:

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");
}



回答4:


Got an answer from the Postgresql JDBC driver mailing list:

You can use the v2 protocol (which inserts parameter values as text, rather than sending them out of line), but you will lose various other bits of driver functionality that depend on the v3 protocol.

Using the V2 protocol worked in forcing the driver to use the simple query protocol instead of the extended query protocol, and brought performance back to levels we were seeing in Python.



来源:https://stackoverflow.com/questions/6741530/any-way-to-not-use-server-side-prepared-statements-in-postgresql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!