6

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.

4 Answers 4

3

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

Sign up to request clarification or add additional context in comments.

Comments

2

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.

1 Comment

It's alluded to in the first document you link to, but the answer turned out to be to use the V2 protocol - see my answer. It is indeed the communication overhead you're seeing.
1

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

1 Comment

I know how to use PreparedStatements, and I typically do. I asked my question because of a particular workload in which prepared statements were causing a 25% slowdown.
1

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.

2 Comments

It is entirely the choice of the driver implementation whether to use the extended query protocol (like JDBC) or the simple one (like Psycopg). There is nothing amiss.
You're right, as I learned later from reading the protocol documentation you pointed out. Edited my answer accordingly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.