Обсуждение: Connection.setReadOnly()

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

Connection.setReadOnly()

От
John R Pierce
Дата:
does Connection.setReadOnly(true) block pgjdbc from automatically
issuing BEGIN;, similar to setAutoCommit(true) ?

if not, why not?



Re: Connection.setReadOnly()

От
Kris Jurka
Дата:

On Thu, 10 Dec 2009, John R Pierce wrote:

> does Connection.setReadOnly(true) block pgjdbc from automatically issuing
> BEGIN;, similar to setAutoCommit(true) ?

No.

> if not, why not?
>

Just because your connection is readonly doesn't mean that everyone elses
is as well.  If you want a consistent view of the database you can get
that with a serializable transaction.

Kris Jurka

Re: Connection.setReadOnly()

От
John R Pierce
Дата:
Kris Jurka wrote:
> Just because your connection is readonly doesn't mean that everyone
> elses is as well.  If you want a consistent view of the database you
> can get that with a serializable transaction.

my oracle developers are screaming bloody murder over this.

they have processes that do nothing but reads.   jdbc tosses a BEGIN;
out automatically.   these processes never Commit(); on a read, why
should they?  so....  we have a fairly large database thats fed a
constant stream of realtime data 24/7 from a factory doing both inserts
and updates...    many different sorts of things have to query this
database, including mechanical/electrical engineering types doing adhoc
queries for oddball reports and such who are not SQL experts.   its way
to easy for them to accidentally create a transaction that they never
end, causing multiday blockage of VACUUM, massive table bloat, etc.

per all my Oracle people this is totally unacceptable and they are ready
to cancel any further postgres projects.

Re: Connection.setReadOnly()

От
Kris Jurka
Дата:

On Thu, 10 Dec 2009, John R Pierce wrote:

> Kris Jurka wrote:
>> Just because your connection is readonly doesn't mean that everyone elses
>> is as well.  If you want a consistent view of the database you can get that
>> with a serializable transaction.
>
> my oracle developers are screaming bloody murder over this.
>
> they have processes that do nothing but reads.   jdbc tosses a BEGIN; out
> automatically.   these processes never Commit(); on a read, why should they?

So if they go to the trouble of doing a setReadOnly call, why not simply
do a setAutoCommit(true) call as well?

Kris Jurka

Re: Connection.setReadOnly()

От
John R Pierce
Дата:
Kris Jurka wrote:
> So if they go to the trouble of doing a setReadOnly call, why not
> simply do a setAutoCommit(true) call as well?

thats pretty much what they'll have to do.   I guess setReadOnly() is
pretty much a non-op in pg-jdbc?

we're having such a problem with Idle in Transaction on this database
that I'm looking into writing a process killer that queries
pg_stat_activity every 10 minutes and does a pg_terminate_backend() on
PIDs older than some arbitrary threshold, maybe an hour.

we're still fixing oraclisms in the main application.    the developers
wanted a mutex on the various 'back end' processes, so they have a
thread that connects, and did a lock on a row in a table (one row for
each named app that has to be a 1-of), then leave that transaction
going.... This works perfectly well on Oracle.     On postgresql, 4-5
days later, its painful to see how much bloat is in this 70GB database,
and in fact, the autovacuum processes start stacking up on each other
and primariy application response time starts shooting up slower and
slower til the factory is slowing down, not good....   I've shown them
how to use pg_try_advisory_lock() to do the same thing.





Re: Connection.setReadOnly()

От
Oliver Jowett
Дата:
John R Pierce wrote:
> Kris Jurka wrote:
>> Just because your connection is readonly doesn't mean that everyone
>> elses is as well.  If you want a consistent view of the database you
>> can get that with a serializable transaction.
>
> my oracle developers are screaming bloody murder over this.
>
> they have processes that do nothing but reads.   jdbc tosses a BEGIN;
> out automatically.   these processes never Commit(); on a read, why
> should they?

Because if they're operating on a connection with autocommit off, the
JDBC spec is very specific about transaction boundaries, and it would
actually be incorrect for the driver *not* to start a transaction. I
have at least one application here that runs readonly queries inside a
transaction specifically because it wants a consistent view.

Does the Oracle driver not follow the JDBC spec here? Or is it just that
long-term open transactions don't cause problems on Oracle?

If your oracle developers don't want manually committed transactions,
perhaps they should.. turn on autocommit.

> per all my Oracle people this is totally unacceptable and they are ready to cancel any further postgres projects.

It's somewhat telling that they identify themselves as "Oracle people".
Postgres isn't identical to Oracle; if you want applications that are
portable between RDBMSes you need to take some care, and presumably they
didn't do this originally and are now paying the price.

-O

Re: Connection.setReadOnly()

От
Oliver Jowett
Дата:
John R Pierce wrote:
> Kris Jurka wrote:
>> So if they go to the trouble of doing a setReadOnly call, why not
>> simply do a setAutoCommit(true) call as well?
>
> thats pretty much what they'll have to do.   I guess setReadOnly() is
> pretty much a non-op in pg-jdbc?

It issues a "SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY"
command. See

http://cvs.pgfoundry.org/cgi-bin/cvsweb.cgi/jdbc/pgjdbc/org/postgresql/jdbc2/AbstractJdbc2Connection.java?rev=1.54&content-type=text/x-cvsweb-markup

-O

Re: Connection.setReadOnly()

От
John R Pierce
Дата:
Oliver Jowett wrote:
> Because if they're operating on a connection with autocommit off, the
> JDBC spec is very specific about transaction boundaries, and it would
> actually be incorrect for the driver *not* to start a transaction. I
> have at least one application here that runs readonly queries inside a
> transaction specifically because it wants a consistent view.
>
> Does the Oracle driver not follow the JDBC spec here? Or is it just that
> long-term open transactions don't cause problems on Oracle?
>

the latter.   long term transactions are not a problem for Oracle.   As
I said, they've been using an open transaction with a row lock as a
MUTEX for an app that runs for weeks or even months.


> If your oracle developers don't want manually committed transactions,
> perhaps they should.. turn on autocommit.
>

otherwise, an app thats doing purely read queries has to periodically
issue a Commit().   I have to say, doing Commit() on read operations is
NOT at all intuitive.


> It's somewhat telling that they identify themselves as "Oracle people".
> Postgres isn't identical to Oracle; if you want applications that are
> portable between RDBMSes you need to take some care, and presumably they
> didn't do this originally and are now paying the price.
>

These two SQL developers have been working on this same family of
manufacturing databases in oracle for like 12-15 years.   Its me thats
calling them 'oracle people' :)





Re: Connection.setReadOnly()

От
Oliver Jowett
Дата:
John R Pierce wrote:
> Oliver Jowett wrote:

>> If your oracle developers don't want manually committed transactions,
>> perhaps they should.. turn on autocommit.
>>
>
> otherwise, an app thats doing purely read queries has to periodically
> issue a Commit().   I have to say, doing Commit() on read operations is
> NOT at all intuitive.

Maybe not, but it's a fairly well known quirk of Postgresql that
long-running transactions don't work so well; the JDBC driver is no
different to any other interface in this regard.

If you don't care about transaction boundaries, why are you even turning
off autocommit in the first place? It's a little unfair to explicitly
turn off autocommit, then complain that you need to manually commit
transactions!

-O

Re: Connection.setReadOnly()

От
Oliver Jowett
Дата:
John R Pierce wrote:
> we have a fairly large database thats fed a
> constant stream of realtime data 24/7 from a factory doing both inserts
> and updates...    many different sorts of things have to query this
> database, including mechanical/electrical engineering types doing adhoc
> queries for oddball reports and such who are not SQL experts.   its way
> to easy for them to accidentally create a transaction that they never
> end, causing multiday blockage of VACUUM, massive table bloat, etc.

Presumably they could also run a query that accidentally consumes all
the CPU and I/O bandwidth on your server (hello missing WHERE clause!)

It sounds like what you need is an intermediate layer that enforces
transaction and query timeouts, rather than giving your mech/eng types
direct access to the DB.

-O

Re: Connection.setReadOnly()

От
John R Pierce
Дата:
Oliver Jowett wrote:
> John R Pierce wrote:
>
>> we have a fairly large database thats fed a
>> constant stream of realtime data 24/7 from a factory doing both inserts
>> and updates...    many different sorts of things have to query this
>> database, including mechanical/electrical engineering types doing adhoc
>> queries for oddball reports and such who are not SQL experts.   its way
>> to easy for them to accidentally create a transaction that they never
>> end, causing multiday blockage of VACUUM, massive table bloat, etc.
>>
>
> Presumably they could also run a query that accidentally consumes all
> the CPU and I/O bandwidth on your server (hello missing WHERE clause!)
>

on the typical server we use with 8 or 16 or more processors, and lots
of fiberchannel bandwidth for storage, they can at most bung up a single
core and some fraction of the total disk IO demand.   the administrators
are fairly used to run away reporting queries in the oracle space, and
will kill them off without hesitation if they are impacting operational
transactions..

> It sounds like what you need is an intermediate layer that enforces
> transaction and query timeouts, rather than giving your mech/eng types
> direct access to the DB.
>

thats kind of hard to do well when you need totally off the wall adhoc
queries to answer complex engineering questions.    on our larger scale
systems we have a seperate dedicated database for reporting queries that
runs on its own hardware, but this postgres system is meant to be a
lower-cost version for a smaller/simpler operation, so the array of
several back end servers we have traditionally used have all been folded
onto this one server (currently the production evaluation server is on
an 8 core Sun v490 with 16GB ram etc).



Re: Connection.setReadOnly()

От
Greg Stark
Дата:
On Fri, Dec 11, 2009 at 12:57 AM, John R Pierce <pierce@hogranch.com> wrote:
>> Does the Oracle driver not follow the JDBC spec here? Or is it just that
>> long-term open transactions don't cause problems on Oracle?
>>
>
> the latter

Well eventually on Oracle you would get a "Snapshot too old" error.
Postgres chooses not to have this unpredictable error and instead have
unpredictable space usage -- it's an inevitable engineering tradeoff.

However recent versions of Oracle have tried various strategies to
reduce the frequency of this error -- likewise recent versions of
Postgres have made efforts to reduce this issue as well. If you use
8.4 you should be much less likely to run into this problem.


--
greg

Re: Connection.setReadOnly()

От
Craig Ringer
Дата:
Oliver Jowett wrote:
> John R Pierce wrote:
>> Oliver Jowett wrote:
>
>>> If your oracle developers don't want manually committed transactions,
>>> perhaps they should.. turn on autocommit.
>>>
>> otherwise, an app thats doing purely read queries has to periodically
>> issue a Commit().   I have to say, doing Commit() on read operations is
>> NOT at all intuitive.
>
> Maybe not, but it's a fairly well known quirk of Postgresql that
> long-running transactions don't work so well; the JDBC driver is no
> different to any other interface in this regard.

Does Pg have issues with long-running read-only transactions in
read-committed mode? Or are they an exception to the usual "avoid
long-running mostly-idle transactions" guideline?

Pg doesn't have to worry about retaining old rows in vacuum with such a
statement, because each new statement creates a new snapshot, so if it's
idle it effectively has _no_ snapshot and vacuum is free to clear old
rows. It doesn't need to keep track of anything to roll back, since the
transaction is read only.

So ... for READ COMMITTED, READ ONLY transactions, _are_ there any
VACUUM issues?

--
Craig Ringer

Re: Connection.setReadOnly()

От
"Albe Laurenz"
Дата:
Greg Stark wrote:
>>> Does the Oracle driver not follow the JDBC spec here? Or is it just that
>>> long-term open transactions don't cause problems on Oracle?
>>
>> the latter
>
> Well eventually on Oracle you would get a "Snapshot too old" error.

Only if the long reading transaction has isolation level
SERIALIZABLE, because with READ COMMITTED it will not need very
old rows from the UNDO tablespace.

Yours,
Laurenz Albe

Re: Connection.setReadOnly()

От
Tom Lane
Дата:
Craig Ringer <craig@postnewspapers.com.au> writes:
> Does Pg have issues with long-running read-only transactions in
> read-committed mode? Or are they an exception to the usual "avoid
> long-running mostly-idle transactions" guideline?

> Pg doesn't have to worry about retaining old rows in vacuum with such a
> statement, because each new statement creates a new snapshot, so if it's
> idle it effectively has _no_ snapshot and vacuum is free to clear old
> rows. It doesn't need to keep track of anything to roll back, since the
> transaction is read only.

As of 8.4, I think the above statements are true.  In prior releases,
transactions just advertised the age of their first snapshot, so an
open transaction created an issue for VACUUM regardless of whether
it was serializable or not.  8.4 has more bookkeeping that allows a
transaction to report that it currently has no live snapshots.

            regards, tom lane

Re: Connection.setReadOnly()

От
John R Pierce
Дата:
Tom Lane wrote:
> As of 8.4, I think the above statements are true.  In prior releases,
> transactions just advertised the age of their first snapshot, so an
> open transaction created an issue for VACUUM regardless of whether
> it was serializable or not.  8.4 has more bookkeeping that allows a
> transaction to report that it currently has no live snapshots.
>

I've been using this...

pgadmin=# select datname,procpid,usename,now() - xact_start as "Age",
current_query from pg_stat_activity where now()-xact_start> interval '30
min' order by xact_start;
 datname | procpid | usename |       Age       |
current_query
---------+---------+---------+-----------------+------------------------------------------------
 lss     |   22528 | fds     | 11:43:15.715747 | <IDLE> in transaction
 lss     |   22979 | fds     | 11:38:27.101715 | <IDLE> in transaction
 lss     |   22980 | fds     | 11:38:27.101676 | <IDLE> in transaction
 lss     |   23150 | fds     | 11:36:39.850232 | <IDLE> in transaction
 lss     |   22987 | pgadmin | 03:38:57.974805 | autovacuum: VACUUM
ANALYZE ts.disc_yield_daily
 lss     |   24272 | pgadmin | 02:37:19.303353 | autovacuum: VACUUM
ANALYZE ts.disc_yield_hour
(6 rows)

to detect old stale transactions and other long running operations

in 8.4, there's a different high water mark I should be using instead?

Re: Connection.setReadOnly()

От
Tom Lane
Дата:
John R Pierce <pierce@hogranch.com> writes:
> I've been using this...
> to detect old stale transactions and other long running operations

> in 8.4, there's a different high water mark I should be using instead?

No, the point of my comment was just that IDLE-in-transaction isn't as
dangerous as it used to be, from the perspective of whether VACUUM can
reclaim dead rows.  There are still lots of other reasons to not want
transactions sitting open without need.  They might be holding locks
for example.

            regards, tom lane