Обсуждение: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

Поиск
Список
Период
Сортировка

9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Thomas Kellerer
Дата:
Hello,

we have switched the Postgres JDBC driver from 9.2-1102 to 9.4-1207 to keep up-to-date.

After we did this our nightly regression tests that test for performance failed
because with the new driver the tests were roughly 30% slower than with
the previous driver (some of them even more than 30%).

After enabling pg_stat_statements in your test environment we found out that some
statements read a *much* higher number of blocks for the query.

Some sample figures (from pg_stat_statements)

One statement:

1102: 710 executions, total time:   845ms, shared_blks_hit =   624765
1207: 710 executions, total time: 30538ms, shared_blks_hit = 15046689

Another one:

1102: 8600 executions, total_time:   68ms, shared_blks_hit =   49500
1102: 8600 executions, total_time: 4035ms, shared_blks_hit = 3419644

The tests have been run against Postgres 9.4.5.

As the tests don't involve any DML, table bloat could be excluded for a reason why
the number of blocks is so high.

It does not affect *all* statements - some statements (also with execution counts
substantially larger than 200) run with the same performance.

So we assumed it had something to do with the execution plans, and the only way
the driver could influence that (while the statement being exactly the same),
was through the server side prepared statements.

So we ran the tests using "prepareThreshold=0" and then the tests with 1207
ran with the same performance as with the 1102 driver.

We have not yet looked at the actual execution plans (e.g. by enabling the
auto-explain module) because using "prepareThreshold=0" is fine for us for now.

So my question is:

Is it possible that the 1207 driver does something different when preparing statements
compared to 1102 that would cause Postgres to use a completely different execution plan?

The 9.3 driver behaves like the 9.2 driver, so the change probably occurred from 9.2 to 9.4
(we didn't test all the 9.4 builds, only the latest)

Regards
Thomas


Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
Here are the details: http://stackoverflow.com/a/32300222/1261287

TL;DR:  pgjdbc automatically uses server-side prepared statements
since 9.4-1202.

Vladimir


Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Thomas Kellerer
Дата:
Vladimir Sitnikov schrieb am 11.01.2016 um 13:56:
> Here are the details: http://stackoverflow.com/a/32300222/1261287
>
> TL;DR:  pgjdbc automatically uses server-side prepared statements
> since 9.4-1202.

Hmm, but the previous drivers also did that, at least the documentation suggests that:

   https://jdbc.postgresql.org/documentation/92/connect.html#connection-parameters

   "The default is five, meaning start using server side prepared statements
    on the fifth execution of the same PreparedStatement object"



Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
The difference is as follows: 1202 can cache across statement.close()
calls. 1201 can't do that.

In other words, to use server-prepared statements in previous
versions, you had to reuse the *same* PreparedStatement *object* again
and again. As soon as you issue .close() you lose your shiny
server-prepared statement.

Typical applications are written in a form of
PreparedStatement ps = con.prepareStatement(sql);
ps.excuteQuery();
ps.close();

In other words, almost always developers just recreate
PreparedStatement and close it.
The improvement of 1202 was to identify such patterns and use
server-prepared statement in such cases as well.
Vladimir


Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Christian Bjørnbak
Дата:
@Vladimir but if 1202+ has become smarter than 1102 and reuse prepared statements more often how come Thomas experience the 1207 to be magnitudes slower?

Shouldn't it be the other way around?



Med venlig hilsen / Kind regards,

Christian Bjørnbak

Chefudvikler / Lead Developer
TouristOnline A/S
Islands Brygge 43
2300 København S
Denmark
TLF: +45 32888230
Dir. TLF: +45 32888235

2016-01-11 14:05 GMT+01:00 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>:
The difference is as follows: 1202 can cache across statement.close()
calls. 1201 can't do that.

In other words, to use server-prepared statements in previous
versions, you had to reuse the *same* PreparedStatement *object* again
and again. As soon as you issue .close() you lose your shiny
server-prepared statement.

Typical applications are written in a form of
PreparedStatement ps = con.prepareStatement(sql);
ps.excuteQuery();
ps.close();

In other words, almost always developers just recreate
PreparedStatement and close it.
The improvement of 1202 was to identify such patterns and use
server-prepared statement in such cases as well.
Vladimir


--
Sent via pgsql-jdbc mailing list (pgsql-jdbc@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-jdbc

Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Dave Cramer
Дата:
It's not that JDBC is slower, it is the plans that are being generated are slower. I can't imagine why that would even happen. 

JDBC doesn't really change the incoming SQL


On 11 January 2016 at 08:29, Christian Bjørnbak <cbj@touristonline.dk> wrote:
@Vladimir but if 1202+ has become smarter than 1102 and reuse prepared statements more often how come Thomas experience the 1207 to be magnitudes slower?

Shouldn't it be the other way around?



Med venlig hilsen / Kind regards,

Christian Bjørnbak

Chefudvikler / Lead Developer
TouristOnline A/S
Islands Brygge 43
2300 København S
Denmark
TLF: +45 32888230
Dir. TLF: +45 32888235

2016-01-11 14:05 GMT+01:00 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>:
The difference is as follows: 1202 can cache across statement.close()
calls. 1201 can't do that.

In other words, to use server-prepared statements in previous
versions, you had to reuse the *same* PreparedStatement *object* again
and again. As soon as you issue .close() you lose your shiny
server-prepared statement.

Typical applications are written in a form of
PreparedStatement ps = con.prepareStatement(sql);
ps.excuteQuery();
ps.close();

In other words, almost always developers just recreate
PreparedStatement and close it.
The improvement of 1202 was to identify such patterns and use
server-prepared statement in such cases as well.
Vladimir


--
Sent via pgsql-jdbc mailing list (pgsql-jdbc@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-jdbc


Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
>I can't imagine why that would even happen.

That can happen in case backend uses "bad plan" for server-prepared statement.

Here are more details:
http://www.postgresql.org/docs/9.4/static/sql-prepare.html
As far as I remember, backend can switch plan on 5th or 6th execution
of server-prepared statement.

>PG DOC: If a prepared statement is executed enough times, the server may eventually decide to save and re-use a
genericplan rather than re-planning each time. This will occur immediately if the prepared statement has no parameters 

In other words, even server-prepared statements can behave differently
from one execution to another.

I've seen a couple of times when a query was fast "the first 5 times",
then backend (9.4) switched to much slower plan.
That happened with exactly the same input value.

The resolution for me was to fix query plan as desired (add offset 0
here and there) so the join order was specific.


On the other hand, I've seen impressive performance improvements for
long queries that take much longer to plan than to execute. Common
wisdom is to hide long SQL into stored procedures (they have
transparent statement cache too), however it can't easily be done for
existing application.

Vladimir


Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Dave Cramer
Дата:



On 11 January 2016 at 08:54, Vladimir Sitnikov <sitnikov.vladimir@gmail.com> wrote:
>I can't imagine why that would even happen.

That can happen in case backend uses "bad plan" for server-prepared statement.

Yes, but we are talking about the same backend with the same SQL, The only difference is the driver. Is that correct ?

Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Thomas Kellerer
Дата:
Vladimir Sitnikov schrieb am 11.01.2016 um 14:05:
> The difference is as follows: 1202 can cache across statement.close()
> calls. 1201 can't do that.
>
> In other words, to use server-prepared statements in previous
> versions, you had to reuse the *same* PreparedStatement *object* again
> and again. As soon as you issue .close() you lose your shiny
> server-prepared statement.
>

Ah, thanks.


Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Edson Richter
Дата:
I can confirm, It really behave differently, but not for the same reason as yours.
In my case, problema is that after optimization at server side, results get different.

I always work with url parameter:

jdbc:postgresql://dbdevel:5433/mydatabase?prepareThreshold=0

When using prepareThreshold=0, I do avoid the server side prepared statements.

My be worth to give a try, since would also makes difference for you as well.


Atenciosamente,

Edson Carlos Ericksson Richter


Em 11/01/2016 11:33, Dave Cramer escreveu:
It's not that JDBC is slower, it is the plans that are being generated are slower. I can't imagine why that would even happen. 

JDBC doesn't really change the incoming SQL


On 11 January 2016 at 08:29, Christian Bjørnbak <cbj@touristonline.dk> wrote:
@Vladimir but if 1202+ has become smarter than 1102 and reuse prepared statements more often how come Thomas experience the 1207 to be magnitudes slower?

Shouldn't it be the other way around?



Med venlig hilsen / Kind regards,

Christian Bjørnbak

Chefudvikler / Lead Developer
TouristOnline A/S
Islands Brygge 43
2300 København S
Denmark
TLF: +45 32888230
Dir. TLF: +45 32888235

2016-01-11 14:05 GMT+01:00 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>:
The difference is as follows: 1202 can cache across statement.close()
calls. 1201 can't do that.

In other words, to use server-prepared statements in previous
versions, you had to reuse the *same* PreparedStatement *object* again
and again. As soon as you issue .close() you lose your shiny
server-prepared statement.

Typical applications are written in a form of
PreparedStatement ps = con.prepareStatement(sql);
ps.excuteQuery();
ps.close();

In other words, almost always developers just recreate
PreparedStatement and close it.
The improvement of 1202 was to identify such patterns and use
server-prepared statement in such cases as well.
Vladimir


--
Sent via pgsql-jdbc mailing list (pgsql-jdbc@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-jdbc





Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
>In my case, problema is that after optimization at server side, results get different.

Do you mean "wrong results" kind of issue?
which driver version are you using?

Generally speaking, it is worth submitting "bad performance when using
prepared statements" issues to PostgreSQL hackers team.
If just a couple of SQLs behave badly due to server-prepared
statements, then it might make sense just tune the statements in
question.
Vladimir


Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Thomas Kellerer
Дата:
Dave Cramer schrieb am 11.01.2016 um 14:56:
> On 11 January 2016 at 08:54, Vladimir Sitnikov <sitnikov.vladimir@gmail.com <mailto:sitnikov.vladimir@gmail.com>>
wrote:
>
>     >I can't imagine why that would even happen.
>
>     That can happen in case backend uses "bad plan" for server-prepared statement.
>
>
> Yes, but we are talking about the same backend with the same SQL, The only difference is the driver. Is that correct
?

Correct.

Identical SQL, identical query parameters, identical order of execution, identical backend, just a different driver
version

Thomas

Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Dave Cramer
Дата:

On 11 January 2016 at 09:44, Thomas Kellerer <spam_eater@gmx.net> wrote:
Dave Cramer schrieb am 11.01.2016 um 14:56:
> On 11 January 2016 at 08:54, Vladimir Sitnikov <sitnikov.vladimir@gmail.com <mailto:sitnikov.vladimir@gmail.com>> wrote:
>
>     >I can't imagine why that would even happen.
>
>     That can happen in case backend uses "bad plan" for server-prepared statement.
>
>
> Yes, but we are talking about the same backend with the same SQL, The only difference is the driver. Is that correct ?

Correct.

Identical SQL, identical query parameters, identical order of execution, identical backend, just a different driver version


Is it possible to get server logs ?



 
Thomas



--
Sent via pgsql-jdbc mailing list (pgsql-jdbc@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-jdbc

Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Thomas Kellerer
Дата:
Dave Cramer schrieb am 11.01.2016 um 15:46:
>
> On 11 January 2016 at 09:44, Thomas Kellerer <spam_eater@gmx.net <mailto:spam_eater@gmx.net>> wrote:
>     > Yes, but we are talking about the same backend with the same SQL, The only difference is the driver. Is that
correct? 
>
>     Correct.
>
>     Identical SQL, identical query parameters, identical order of execution, identical backend, just a different
driverversion 
>
>
> Is it possible to get server logs ?

If that is helpful, I think I can arrange that.

Which logging settings would you like to have for that?






Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Dave Cramer
Дата:
I just want to see what the server sees for SQL statements with the different drivers.

The easiest way I find is to set log_min_duration to 0 which logs everything and then you can change it back


On 11 January 2016 at 09:54, Thomas Kellerer <spam_eater@gmx.net> wrote:
Dave Cramer schrieb am 11.01.2016 um 15:46:
>
> On 11 January 2016 at 09:44, Thomas Kellerer <spam_eater@gmx.net <mailto:spam_eater@gmx.net>> wrote:
>     > Yes, but we are talking about the same backend with the same SQL, The only difference is the driver. Is that correct ?
>
>     Correct.
>
>     Identical SQL, identical query parameters, identical order of execution, identical backend, just a different driver version
>
>
> Is it possible to get server logs ?

If that is helpful, I think I can arrange that.

Which logging settings would you like to have for that?








--
Sent via pgsql-jdbc mailing list (pgsql-jdbc@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-jdbc

Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
Thomas, as far as I see, you have offending queries and bind values
for them, don't you?

Can you please perform the following dance in psql or pgadmin?

PREPARE prep1207(number,number,number,number,number,number) as -- <--
data types for the bind variables
select .. $1, ... where id=$2;  -- <-- your query here

EXPLAIN ANALYZE EXECUTE prep1207(1,2,3,42,100500); -- <-- values for
bind variables
EXPLAIN ANALYZE EXECUTE prep1207(1,2,3,42,100500); -- <-- values for
bind variables
EXPLAIN ANALYZE EXECUTE prep1207(1,2,3,42,100500); -- <-- values for
bind variables
EXPLAIN ANALYZE EXECUTE prep1207(1,2,3,42,100500); -- <-- values for
bind variables
EXPLAIN ANALYZE EXECUTE prep1207(1,2,3,42,100500); -- <-- values for
bind variables

Ideally, it should reproduce the issue. In other words, 5th or 6th
execution should flip to bad plan.

Then share the plan/query.
If table names cannot be made public, you might want try
http://explain.depesz.com/ to anonymize the plan.

Vladimir


Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Thomas Kellerer
Дата:
Dave Cramer schrieb am 11.01.2016 um 15:56:
> I just want to see what the server sees for SQL statements with the different drivers.
>
> The easiest way I find is to set log_min_duration to 0 which logs everything and then you can change it back
>

I'll see what I can do.

We will have to anonymize the statements somehow because for legal reasons I can't disclose them.

Thomas


I'm using 1201 driver. No matter JDK 7 or JDK 8.
Big real issue for me: after third query, the prepareThresold is hit,
and timezone data is converted "on the fly" to "timezone without
daylights" for timestamp fields.
Data is stored in database as "2015-09-30 00:00:00", in the 1st to 3rd
query returns with "2015-09-30 00:00:00", and the 4º and on returns
"2015-09-29 23:00:00".

Disabling with prepareThreshold=0 solved the problem once for all.
I had no further time to investigate and/or produce a case for asking
for a fix.

Regards,

Atenciosamente,

Edson Carlos Ericksson Richter

Em 11/01/2016 12:14, Vladimir Sitnikov escreveu:
>> In my case, problema is that after optimization at server side, results get different.
> Do you mean "wrong results" kind of issue?
> which driver version are you using?
>
> Generally speaking, it is worth submitting "bad performance when using
> prepared statements" issues to PostgreSQL hackers team.
> If just a couple of SQLs behave badly due to server-prepared
> statements, then it might make sense just tune the statements in
> question.
> Vladimir
>
>



Warning:

This only happens if your country has Daylights Saving Time active.
In Brazil, default timezone is GMT-03:00. Currently in DST, the timezone
is GMT-02:00.
This seems to affect some kind of value conversion, and subtract 1 hour
from timestamp values.

Atenciosamente,

Edson Carlos Ericksson Richter

Em 11/01/2016 14:15, Edson Richter escreveu:
> I'm using 1201 driver. No matter JDK 7 or JDK 8.
> Big real issue for me: after third query, the prepareThresold is hit,
> and timezone data is converted "on the fly" to "timezone without
> daylights" for timestamp fields.
> Data is stored in database as "2015-09-30 00:00:00", in the 1st to 3rd
> query returns with "2015-09-30 00:00:00", and the 4º and on returns
> "2015-09-29 23:00:00".
>
> Disabling with prepareThreshold=0 solved the problem once for all.
> I had no further time to investigate and/or produce a case for asking
> for a fix.
>
> Regards,
>
> Atenciosamente,
>
> Edson Carlos Ericksson Richter
>
> Em 11/01/2016 12:14, Vladimir Sitnikov escreveu:
>>> In my case, problema is that after optimization at server side,
>>> results get different.
>> Do you mean "wrong results" kind of issue?
>> which driver version are you using?
>>
>> Generally speaking, it is worth submitting "bad performance when using
>> prepared statements" issues to PostgreSQL hackers team.
>> If just a couple of SQLs behave badly due to server-prepared
>> statements, then it might make sense just tune the statements in
>> question.
>> Vladimir
>>
>>
>
>
>



Can you put more details on the APIs you use to retrieve the data?
.getTimestamp(int)?
.getTimestamp(int, Calendar)?
.getString(int)?
.getObject(int)?
Vladimir


Actually, I don't know.

I'm using EclipseLink as layer before the database.
Since my Java classes are annotated with @Temporal(TIMESTAMP), I do
understand EclipseLink will be using getTimeStamp - but I can't tell for
sure.
Also, when looking data using "pgAdmin" timestamp data appears normal.
But if querying data using NetBeans SQL explorer or ART (reporting
tool), I get exactly same issue as with EclipseLink.
I suppose NetBeans and ART use getObject, but it is mere speculation
from my side.

As said before, since prepareThreshold=0 solved my problem, and I have a
time shortage last few months, I'll try to investigate further in near
future.
Sorry not being of great help right now.

Regards,

Atenciosamente,

Edson Carlos Ericksson Richter

Em 11/01/2016 17:50, Vladimir Sitnikov escreveu:
> Can you put more details on the APIs you use to retrieve the data?
> .getTimestamp(int)?
> .getTimestamp(int, Calendar)?
> .getString(int)?
> .getObject(int)?
> Vladimir
>
>



What is the field type?
timestamp? timestamp with time zone?

Are you using the latest java timezone updates? (tzupdater)

>As said before, since prepareThreshold=0 solved my problem

Then
binaryTransferDisable=DATE,DATE_ARRAY,TIMESTAMP,TIMESTAMP_ARRAY,TIMESTAMPTZ,TIMESTAMPTZ_ARRAY,TIME,TIME_ARRAY,TIMETZ,TIMETZ_ARRAY
connection property might be better workaround.

Vladimir


This is really interesting.
I would give a try.

Regards,

Atenciosamente,

Edson Carlos Ericksson Richter

Em 11/01/2016 18:42, Vladimir Sitnikov escreveu:
> What is the field type?
> timestamp? timestamp with time zone?
>
> Are you using the latest java timezone updates? (tzupdater)
>
>> As said before, since prepareThreshold=0 solved my problem
> Then
binaryTransferDisable=DATE,DATE_ARRAY,TIMESTAMP,TIMESTAMP_ARRAY,TIMESTAMPTZ,TIMESTAMPTZ_ARRAY,TIME,TIME_ARRAY,TIMETZ,TIMETZ_ARRAY
> connection property might be better workaround.
>
> Vladimir



Here's the fix:
https://github.com/pgjdbc/pgjdbc/commit/642b48a787098a6c5a068710bdbbf9f1b11f3aac

You can try it via Maven Central's <version>9.4.1208-SNAPSHOT</version>


I wonder if there is anybody from Portugal on the list?
Can you explain how you represent 2000-03-26 00:00:00?

As far as I understand, somewhere near 26th March Atlantic/Azores
skips from 00:00:00 to 01:00:00.
See http://www.timeanddate.com/time/change/portugal/ponta-delgada-azores
for 2000-03-26 00:00:00 -> 01:00:00

This causes troubles since java.util.Date is supposed to be 2000-03-26
00:00:00 Atlantic/Azores, however there is no such thing like
"2000-03-26 00:00:00 Atlantic/Azores" in Java.
If you try to use calendar.set(Calendar.HOUR_OF_DAY, 0), then you get
01:00:00 back.

This caused me to add exception to the expected results:

https://github.com/pgjdbc/pgjdbc/commit/642b48a787098a6c5a068710bdbbf9f1b11f3aac#diff-b318f589843d60530d1eada03263c1b0R895

Vladimir


Even though the particular case with DATE is fixed, I would still
recommend to consider timestamptz data type.

DATE has inherent timezone problems, so if you are storing time
instants, then you'd better operate on timestamptz.
See "2000-03-26 00:00:00 Atlantic/Azores problem" above.

Vladimir




> Date: Tue, 12 Jan 2016 01:31:37 +0300
> Subject: Re: Driver behaves differently with prepareThreshold and timestamp fields when daylights is active (was Re: [JDBC] Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102)
> From: sitnikov.vladimir@gmail.com
> To: edsonrichter@hotmail.com; pgsql-jdbc@postgresql.org
>
> Here's the fix:
> https://github.com/pgjdbc/pgjdbc/commit/642b48a787098a6c5a068710bdbbf9f1b11f3aac
>
> You can try it via Maven Central's <version>9.4.1208-SNAPSHOT</version>

Uau, that was fast!!!
I'll try to download a build, and then test the fix.

>
>
> I wonder if there is anybody from Portugal on the list?
> Can you explain how you represent 2000-03-26 00:00:00?

I'm on Brazil, and we are on DST right now. In Brazil, "2000-03-26 00:00:00" would be better shown as "26/03/2000 00:00:00".

 
Regards,

Edson

>
> As far as I understand, somewhere near 26th March Atlantic/Azores
> skips from 00:00:00 to 01:00:00.
> See http://www.timeanddate.com/time/change/portugal/ponta-delgada-azores
> for 2000-03-26 00:00:00 -> 01:00:00
>
> This causes troubles since java.util.Date is supposed to be 2000-03-26
> 00:00:00 Atlantic/Azores, however there is no such thing like
> "2000-03-26 00:00:00 Atlantic/Azores" in Java.
> If you try to use calendar.set(Calendar.HOUR_OF_DAY, 0), then you get
> 01:00:00 back.
>
> This caused me to add exception to the expected results:
> https://github.com/pgjdbc/pgjdbc/commit/642b48a787098a6c5a068710bdbbf9f1b11f3aac#diff-b318f589843d60530d1eada03263c1b0R895
>
> Vladimir

Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Thomas Kellerer
Дата:
> Is it possible to get server logs ?

I have picked out one of the statements that suffered from this and sanitized the logfile.

   http://sql-workbench.net/pg_jdbc_94.log

The complete statement is at the top of the file and in the messages themselves,
I have replaced each occurrence of the statement with "select ...."

The interesting thing (at least for me) is that the first few executions of the
server side statement have pretty much the same runtime as the ones before the prepare.
And then suddenly the runtime shoots through the rough going up from 1ms to 40ms or even 60ms

Regards
Thomas


Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
>And then suddenly the runtime shoots through the rough going up from 1ms to 40ms or even 60ms

Can it be data-dependent?
Can you try using the same input values for multiple executions?

Vladimir


Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Thomas Kellerer
Дата:
Vladimir Sitnikov schrieb am 12.01.2016 um 11:44:
>> And then suddenly the runtime shoots through the rough going up from 1ms to 40ms or even 60ms
>
> Can it be data-dependent?

Apparently the server chooses a bad execution plan when a server side prepared
statement is used - it is very likely because of the parameter placeholders
that don't allow Postgres to evaluate the correct cardinality and it
creates a "one size fits all plan"

My guess is that the plan that is generated using the prepared statement only
works for some input values, but not for all (a problem that Oracle has suffered
from for ages as well). As I have written previously we didn't bother to enable the
auto-explain module to see where Postgres goes wrong in the planning because using
prepareThreshold=0 is good enough for us.

Given my experience with bad plans for parametrized statements in Oracle I think it is
definitely the better choice to not use server side prepared statements - at least for
this application.

> Can you try using the same input values for multiple executions?

The tests we are running are pretty much pre-defined. Re-working them would probably be a bigger deal.
Plus I am not directly involved in that project, so I am actually relaying everything here ;)

Regards
Thomas






Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
>My guess is that the plan that is generated using the prepared statement only
works for some input values, but not for all (a problem that Oracle has suffered
from for ages as well).

I think the problem is as follows:
1) During initial runs in server-prepared mode PG still uses exact
values to plan the query
2) It turns out that for certain conditions PG properly understands
that certain conditions are bad.
I bet $1 = '180', $2 = '1' returns lots of rows, thus backend chooses
to start with $3 = '7728'.
3) Later backend creates generic plan. That one does not include
knowledge of exact $1 and &2 values. Thus backend estimates the
cardinality differently.
That results a plan flip.

Note: in Oracle (9-10) bind peeking worked in another way.
There, a plan built for the first bind values was reused for all the
subsequent executions.
That makes more sense for me since that gives at least some stability
(it avoids sudden plan flips).

I'll try to file a case to hackers list to check what they say on the plan flip.

PS. The sad thing is JDBC does have room for "SQL-injection-safe,
non-server-prepared query". In other words, plain java.sql.Statement
does not have "setXXX" methods, and PreparedStatement has no
user-provided API to convey "please, do not use server-prepared
statement as the plan is very data-dependent".

PPS. I do not think the plan is data-dependent in the particular case.
I bet the same plan works for all the values that particular
application uses. It is just PG's fault that plan flip happens.

Vladimir


Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Dave Cramer
Дата:
Actually around 9.2 Tom Lane added the ability to have multiple plans for prepared statements, specifically

Allow the planner to generate custom plans for specific parameter values even when using prepared statement

What version of the server are you using ?


On 12 January 2016 at 06:26, Vladimir Sitnikov <sitnikov.vladimir@gmail.com> wrote:
>My guess is that the plan that is generated using the prepared statement only
works for some input values, but not for all (a problem that Oracle has suffered
from for ages as well).

I think the problem is as follows:
1) During initial runs in server-prepared mode PG still uses exact
values to plan the query
2) It turns out that for certain conditions PG properly understands
that certain conditions are bad.
I bet $1 = '180', $2 = '1' returns lots of rows, thus backend chooses
to start with $3 = '7728'.
3) Later backend creates generic plan. That one does not include
knowledge of exact $1 and &2 values. Thus backend estimates the
cardinality differently.
That results a plan flip.

Note: in Oracle (9-10) bind peeking worked in another way.
There, a plan built for the first bind values was reused for all the
subsequent executions.
That makes more sense for me since that gives at least some stability
(it avoids sudden plan flips).

I'll try to file a case to hackers list to check what they say on the plan flip.

PS. The sad thing is JDBC does have room for "SQL-injection-safe,
non-server-prepared query". In other words, plain java.sql.Statement
does not have "setXXX" methods, and PreparedStatement has no
user-provided API to convey "please, do not use server-prepared
statement as the plan is very data-dependent".

PPS. I do not think the plan is data-dependent in the particular case.
I bet the same plan works for all the values that particular
application uses. It is just PG's fault that plan flip happens.

Vladimir


--
Sent via pgsql-jdbc mailing list (pgsql-jdbc@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-jdbc

Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
I'm using "PostgreSQL 9.4.4 on x86_64-unknown-linux-gnu, compiled by
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11), 64-bit"

Vladimir


Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Albe Laurenz
Дата:
Vladimir Sitnikov wrote:
> >My guess is that the plan that is generated using the prepared statement only
> works for some input values, but not for all (a problem that Oracle has suffered
> from for ages as well).
> 
> I think the problem is as follows:
> 1) During initial runs in server-prepared mode PG still uses exact
> values to plan the query
> 2) It turns out that for certain conditions PG properly understands
> that certain conditions are bad.
> I bet $1 = '180', $2 = '1' returns lots of rows, thus backend chooses
> to start with $3 = '7728'.
> 3) Later backend creates generic plan. That one does not include
> knowledge of exact $1 and &2 values. Thus backend estimates the
> cardinality differently.
> That results a plan flip.
> 
> Note: in Oracle (9-10) bind peeking worked in another way.
> There, a plan built for the first bind values was reused for all the
> subsequent executions.
> That makes more sense for me since that gives at least some stability
> (it avoids sudden plan flips).
> 
> I'll try to file a case to hackers list to check what they say on the plan flip.

I didn't look at the specific query, but I have seen cases like that before.

During the first 5 executions, PostgreSQL generates a specific plan
and remembers the *estimated* cost.
After that, the cost for the generic plan (with $1, $2, ...) is
estimated and compared to the average of the estimated costs of
the previous specific plans.
If the generic plan is no worse, it is used from then on.

The problem is that only estimates are compared.
The performance drop from the sixth execution on usually means that
the cost estimate for the generic plan is off.

It would be helpful to create a prepared statement, and on the sixth
execution capture the output of
EXPLAIN (ANALYZE, BUFFERS) EXECUTE mystmt(args);

Analyzing that should help you find out where things go wrong.

Yours,
Laurenz Albe

Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Dave Cramer
Дата:
Yes, we are aware of the change from the 5th to the 6th iteration. This is not the problem. The 5th, and 6th iteration are pretty close, the problem occurs further down


On 12 January 2016 at 07:15, Albe Laurenz <laurenz.albe@wien.gv.at> wrote:
Vladimir Sitnikov wrote:
> >My guess is that the plan that is generated using the prepared statement only
> works for some input values, but not for all (a problem that Oracle has suffered
> from for ages as well).
>
> I think the problem is as follows:
> 1) During initial runs in server-prepared mode PG still uses exact
> values to plan the query
> 2) It turns out that for certain conditions PG properly understands
> that certain conditions are bad.
> I bet $1 = '180', $2 = '1' returns lots of rows, thus backend chooses
> to start with $3 = '7728'.
> 3) Later backend creates generic plan. That one does not include
> knowledge of exact $1 and &2 values. Thus backend estimates the
> cardinality differently.
> That results a plan flip.
>
> Note: in Oracle (9-10) bind peeking worked in another way.
> There, a plan built for the first bind values was reused for all the
> subsequent executions.
> That makes more sense for me since that gives at least some stability
> (it avoids sudden plan flips).
>
> I'll try to file a case to hackers list to check what they say on the plan flip.

I didn't look at the specific query, but I have seen cases like that before.

During the first 5 executions, PostgreSQL generates a specific plan
and remembers the *estimated* cost.
After that, the cost for the generic plan (with $1, $2, ...) is
estimated and compared to the average of the estimated costs of
the previous specific plans.
If the generic plan is no worse, it is used from then on.

The problem is that only estimates are compared.
The performance drop from the sixth execution on usually means that
the cost estimate for the generic plan is off.

It would be helpful to create a prepared statement, and on the sixth
execution capture the output of
EXPLAIN (ANALYZE, BUFFERS) EXECUTE mystmt(args);

Analyzing that should help you find out where things go wrong.

Yours,
Laurenz Albe

--
Sent via pgsql-jdbc mailing list (pgsql-jdbc@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-jdbc

Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Jeremy Whiting
Дата:
On 12/01/16 11:26, Vladimir Sitnikov wrote:
>> My guess is that the plan that is generated using the prepared statement only
> works for some input values, but not for all (a problem that Oracle has suffered
> from for ages as well).
>
> I think the problem is as follows:
> 1) During initial runs in server-prepared mode PG still uses exact
> values to plan the query
  Most types in the driver map directly but date time parameters are
special. There may be others treated as a special case.

  I think you'll find initial executions (Bind) use the paramater type
org.postgresql.core.Oid.UNSPECIFIED for the date time.
https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java#L1426
> 2) It turns out that for certain conditions PG properly understands
> that certain conditions are bad.
> I bet $1 = '180', $2 = '1' returns lots of rows, thus backend chooses
> to start with $3 = '7728'.
  At the threshold a ParameterDescribe is issued by the front end. The
back end returns the actual type used to store the parameter. The front
end stores the updated parameter type information.
> 3) Later backend creates generic plan. That one does not include
> knowledge of exact $1 and &2 values. Thus backend estimates the
> cardinality differently.
  Subsequent Bind messages use the replaced parameter type. The back end
switches to a new plan using the updated type information.

  I could be wrong on this as the codebase has changed dramatically in
recent weeks.

Jeremy
> That results a plan flip.
>
> Note: in Oracle (9-10) bind peeking worked in another way.
> There, a plan built for the first bind values was reused for all the
> subsequent executions.
> That makes more sense for me since that gives at least some stability
> (it avoids sudden plan flips).
>
> I'll try to file a case to hackers list to check what they say on the plan flip.
>
> PS. The sad thing is JDBC does have room for "SQL-injection-safe,
> non-server-prepared query". In other words, plain java.sql.Statement
> does not have "setXXX" methods, and PreparedStatement has no
> user-provided API to convey "please, do not use server-prepared
> statement as the plan is very data-dependent".
>
> PPS. I do not think the plan is data-dependent in the particular case.
> I bet the same plan works for all the values that particular
> application uses. It is just PG's fault that plan flip happens.
>
> Vladimir
>
>


--
Jeremy Whiting
Senior Software Engineer, JBoss Performance Team
Red Hat

------------------------------------------------------------
Registered Address: RED HAT UK LIMITED, 64 Baker Street, 4th Floor, Paddington. London. United Kingdom W1U 7DF
Registered in UK and Wales under Company Registration No. 3798903  Directors: Michael Cunningham (US), Charles Peters
(US),Matt Parson (US) and Michael O'Neill(Ireland) 



Re: Re: 9.4-1207 behaves differently with server side prepared statements compared to 9.2-1102

От
Vladimir Sitnikov
Дата:
Jeremy,

The issue is easily reproducible in plain psql.
It has nothing to do with jdbc driver.
It has nothing to do with date-time either.

> I think you'll find initial executions (Bind) use the paramater type org.postgresql.core.Oid.UNSPECIFIED for the date
time.

Does $1 = '180', $2 = '1' or $3 = '7728' look like a date-time value?

Vladimir