Thread: [GENERAL] Non-overlapping updates blocking each other
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
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.
I reserve the right to fantasize. Whether or not you
wish to share my fantasy is entirely up to you.
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
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.
I reserve the right to fantasize. Whether or not you
wish to share my fantasy is entirely up to you.
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
> 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
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.
I reserve the right to fantasize. Whether or not you
wish to share my fantasy is entirely up to you.
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
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
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
> 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
> > 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