Consider the following when the transaction isolation level is Read Committed (the default):
UPDATE example
SET foo = 'bar'
WHERE ...
and
DELETE FROM example
WHERE ...
Neither DELETE
nor UPDATE
supports ORDER BY
, nor do they have a defined order. After reading the PostgreSQL docs extensively, it would seem the most simple and reliable solution to avoid deadlock in a concurrent environment is
UPDATE example
SET foo = 'bar'
WHERE ctid IN (
SELECT ctid
FROM example
WHERE ...
ORDER BY ctid
FOR UPDATE
)
I'm not thrilled about doing this to every UPDATE
and DELETE
that affects multiple rows.
- Is my assessment and solution correct?
- Is this the best solution?
- Is there a reason PostgreSQL doesn't already do this automatically?
Best Answer
Your assessment is spot on, and there is no better way of doing it.
As an alternative, you could do without the sort, but delete in smaller batches, each in its own transaction. That is still susceptible to deadlock, but the likelihood is smaller, and re-running the transaction doesn't hurt quite as much.