Thread: [GENERAL] Non-overlapping updates blocking each other

[GENERAL] Non-overlapping updates blocking each other

From
Seamus Abshere
Date:
hi,

I've got 2 updates on non-overlapping uuid (primary key) ranges. For
example:

UPDATE [...] WHERE id BETWEEN 'ff000000-0000-0000-0000-000000000000' AND
'ff0fffff-ffff-ffff-ffff-ffffffffffff'
and
UPDATE [...] WHERE id BETWEEN 'f8c00000-0000-0000-0000-000000000000' AND
'f8ffffff-ffff-ffff-ffff-ffffffffffff'

Yet one blocks the other one. How is this possible?

Thanks,
Seamus

--
Seamus Abshere, SCEA
https://www.faraday.io
https://github.com/seamusabshere
https://linkedin.com/in/seamusabshere


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

Re: [GENERAL] Non-overlapping updates blocking each other

From
Melvin Davidson
Date:


On Sat, Oct 14, 2017 at 10:30 AM, Seamus Abshere <seamus@abshere.net> wrote:
hi,

I've got 2 updates on non-overlapping uuid (primary key) ranges. For
example:

UPDATE [...] WHERE id BETWEEN 'ff000000-0000-0000-0000-000000000000' AND
'ff0fffff-ffff-ffff-ffff-ffffffffffff'
and
UPDATE [...] WHERE id BETWEEN 'f8c00000-0000-0000-0000-000000000000' AND
'f8ffffff-ffff-ffff-ffff-ffffffffffff'

Yet one blocks the other one. How is this possible?

Thanks,
Seamus

--
Seamus Abshere, SCEA
https://www.faraday.io
https://github.com/seamusabshere
https://linkedin.com/in/seamusabshere


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

Have you done and EXPLAIN on each of the updates?
More than likely, the optimizer has determined that a table scan is best, in which case it will use a table lock.
That means one updates will be blocking each other.

You can also execute the following query and check the wait_event_type to verify.

SELECT c.datname,
       c.pid as pid,
       c.client_addr,
       c.usename as user,
       c.query,
       c.wait_event,
       c.wait_event_type,
      l.pid as blocked_by,
       c.query_start,
       current_timestamp - c.query_start as duration
  FROM pg_stat_activity c
  LEFT JOIN pg_locks l1 ON (c.pid = l1.pid and not l1.granted)
  LEFT JOIN pg_locks l2 on (l1.relation = l2.relation and l2.granted)
  LEFT JOIN pg_stat_activity l ON (l2.pid = l.pid)
  LEFT JOIN pg_stat_user_tables t ON (l1.relation = t.relid)
 WHERE pg_backend_pid() <> c.pid
ORDER BY datname,
         query_start;

--
Melvin Davidson
I reserve the right to fantasize.  Whether or not you
wish to share my fantasy is entirely up to you.

Re: [GENERAL] Non-overlapping updates blocking each other

From
Thomas Kellerer
Date:
Melvin Davidson schrieb am 14.10.2017 um 17:32:
> More than likely, the optimizer has determined that a table scan is best, in which case it will use a table lock.
> That means one updates will be blocking each other.

Since when does Postgres lock the whole table during an update?





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

Re: [GENERAL] Non-overlapping updates blocking each other

From
Melvin Davidson
Date:


On Sat, Oct 14, 2017 at 12:01 PM, Thomas Kellerer <spam_eater@gmx.net> wrote:
Melvin Davidson schrieb am 14.10.2017 um 17:32:
More than likely, the optimizer has determined that a table scan is best, in which case it will use a table lock.
That means one updates will be blocking each other.

Since when does Postgres lock the whole table during an update?






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


>Since when does Postgres lock the whole table during an update?
When the optimizer thinks it needs to do a TABLE SCAN!

--
Melvin Davidson
I reserve the right to fantasize.  Whether or not you
wish to share my fantasy is entirely up to you.

Re: [GENERAL] Non-overlapping updates blocking each other

From
Tom Lane
Date:
Melvin Davidson <melvin6925@gmail.com> writes:
> On Sat, Oct 14, 2017 at 12:01 PM, Thomas Kellerer <spam_eater@gmx.net>
> wrote:
>> Since when does Postgres lock the whole table during an update?

> When the optimizer thinks it needs to do a TABLE SCAN!

Sorry, but that's nonsense.

More likely explanations for the OP's problem involve foreign key
constraints that cause two different row updates to need to lock
the same referenced row, or maybe he's using some index type that
has greater locking demands than a btree, or he's using serializable
mode and fell foul of one of its approximations as to which rows
the update depends on, or perhaps some other corner case.  We'd need
more info about the schema and the Postgres version to tell for sure.
        regards, tom lane


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

Re: [GENERAL] Non-overlapping updates blocking each other

From
Seamus Abshere
Date:
> On Sat, Oct 14, 2017 at 10:30 AM, Seamus Abshere <seamus@abshere.net>
> > UPDATE [...] WHERE id BETWEEN 'ff000000-0000-0000-0000-000000000000' AND
> > 'ff0fffff-ffff-ffff-ffff-ffffffffffff'
> > and
> > UPDATE [...] WHERE id BETWEEN 'f8c00000-0000-0000-0000-000000000000' AND
> > 'f8ffffff-ffff-ffff-ffff-ffffffffffff'
> > Yet one blocks the other one. How is this possible?

On Sat, Oct 14, 2017, at 12:32 PM, Melvin Davidson wrote:
> More than likely, the optimizer has determined that a table scan is best,
> in which case it will use a table lock.
> You can also execute the following query and check the wait_event_type to
> verify.

hi Melvin,

Very interesting! The result:

wait_event      | page
wait_event_type | Lock

So I guess this means that the ids don't overlap, but they are sometimes
found in the same page, and the whole page gets locked?

Any narrative (pretending I don't know anything) would be very helpful.

Thanks!
Seamus

PS. I do a SELECT 1 FROM x WHERE [ID_RANGE] FOR UPDATE right before the
update, but that's to prevent a race condition. The id ranges still
don't overlap.


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

Re: [GENERAL] Non-overlapping updates blocking each other

From
Melvin Davidson
Date:


On Sun, Oct 15, 2017 at 8:01 AM, Seamus Abshere <seamus@abshere.net> wrote:
> On Sat, Oct 14, 2017 at 10:30 AM, Seamus Abshere <seamus@abshere.net>
> > UPDATE [...] WHERE id BETWEEN 'ff000000-0000-0000-0000-000000000000' AND
> > 'ff0fffff-ffff-ffff-ffff-ffffffffffff'
> > and
> > UPDATE [...] WHERE id BETWEEN 'f8c00000-0000-0000-0000-000000000000' AND
> > 'f8ffffff-ffff-ffff-ffff-ffffffffffff'
> > Yet one blocks the other one. How is this possible?

On Sat, Oct 14, 2017, at 12:32 PM, Melvin Davidson wrote:
> More than likely, the optimizer has determined that a table scan is best,
> in which case it will use a table lock.
> You can also execute the following query and check the wait_event_type to
> verify.

hi Melvin,

Very interesting! The result:

wait_event      | page
wait_event_type | Lock

So I guess this means that the ids don't overlap, but they are sometimes
found in the same page, and the whole page gets locked?

Any narrative (pretending I don't know anything) would be very helpful.

Thanks!
Seamus

PS. I do a SELECT 1 FROM x WHERE [ID_RANGE] FOR UPDATE right before the
update, but that's to prevent a race condition. The id ranges still
don't overlap.

Seamus,

As Tom suggests, to get an exact cause of your problem, it is very important we get the following additional information

1. Exact PostgreSQL version. IE: SELECT  version();
2. Your O/S
3. The full structure of your table in query, including constraints
4. The full, exact queries.
5. The FULL output from the query I gave you.

--
Melvin Davidson
I reserve the right to fantasize.  Whether or not you
wish to share my fantasy is entirely up to you.

Re: [GENERAL] Non-overlapping updates blocking each other

From
Seamus Abshere
Date:
On 2017-10-14 16:32:33 Tom Lane wrote:
> More likely explanations for the OP's problem involve foreign key
> constraints that cause two different row updates to need to lock
> the same referenced row, or maybe he's using some index type that
> has greater locking demands than a btree, or he's using serializable

hi Tom,

I hesitate to share my query and indexes because it makes this question
seem more esoteric than I think it really is... but here we go.

* Version 9.6.3.
* I don't have any foreign key constraints.
* I don't use serializable.
* My update query is very careful to stay in an id range. [1]
* I do have some exotic indexes [2]. gist, gin, postgis, fillfactor...

My current theory is that, since the table is not clustered by id, rows
with very distant ids get stored in the same page, and the whole page is
locked during an update. Or something.

[1] Update SQL:
https://gist.github.com/seamusabshere/d04dad259e383c13f5559241d2fcad70

[2] Indexes:
https://gist.github.com/seamusabshere/acba364b97e1dd221a589b1aaf22bddb

Thanks,
Seamus


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

Re: [GENERAL] Non-overlapping updates blocking each other

From
Alvaro Herrera
Date:
Did you try using SELECT FOR NO KEY UPDATE instead of SELECT FOR UPDATE?

However:

Seamus Abshere wrote:

> My current theory is that, since the table is not clustered by id, rows
> with very distant ids get stored in the same page, and the whole page is
> locked during an update.

But we only lock one heap page at a time, not many, so it's hard to see
how that would deadlock.

> Or something.

Given your reluctance to share more details, it seems you'd have to do
with that explanation.

-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services


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

Re: [GENERAL] Non-overlapping updates blocking each other

From
Tom Lane
Date:
Seamus Abshere <seamus@abshere.net> writes:
> I hesitate to share my query and indexes because it makes this question
> seem more esoteric than I think it really is... but here we go.
> * Version 9.6.3.
> * I don't have any foreign key constraints.
> * I don't use serializable.
> * My update query is very careful to stay in an id range. [1]
> * I do have some exotic indexes [2]. gist, gin, postgis, fillfactor...

I'd bet on the last one, especially since you found that the problem
was a page-level lock.  Did you look to see which relation the page
lock was in?
        regards, tom lane


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

Re: [GENERAL] Non-overlapping updates blocking each other

From
Seamus Abshere
Date:
> Seamus Abshere <seamus@abshere.net> writes:
> > * I do have some exotic indexes [2]. gist, gin, postgis, fillfactor...

> On Mon, Oct 16, 2017, at 10:55 AM, Tom Lane wrote:
> I'd bet on the last one, especially since you found that the problem
> was a page-level lock.  Did you look to see which relation the page
> lock was in?

The specific relation varies, but it appears to always be compound GIN
index on (jsonb, text)

Can I like decrease the fillfactor or something to make these
"collisions" less frequent?


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

Re: [GENERAL] Non-overlapping updates blocking each other

From
Seamus Abshere
Date:
> > On Mon, Oct 16, 2017, at 10:55 AM, Tom Lane wrote:
> > I'd bet on the last one, especially since you found that the problem
> > was a page-level lock.  Did you look to see which relation the page
> > lock was in?

On Mon, Oct 16, 2017, at 12:34 PM, Seamus Abshere wrote:
> The specific relation varies, but it appears to always be compound GIN
> index on (jsonb, text)

This is definitely GIN fastupdate. I turned off fastupdate and the
blocks go away. I have a feeling, however, that my UPDATEs will actually
get slower (testing now).

I'm most interested in the fastest UPDATEs possible, even if reads
suffer or similar UPDATEs take wildly different amounts of time.

Should I crank maintenance_work_mem and gin_pending_list_limit  way up,
and autovacuum thresholds way down?


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