In my Ruby on Rails 4 app, I have this query to a Postgres 9.4 database:
@chosen_opportunity = Opportunity.find_by_sql(
" UPDATE \"opportunities\" s
SET opportunity_available = false
FROM (
SELECT \"opportunities\".*
FROM \"opportunities\"
WHERE ( deal_id = #{@deal.id}
AND opportunity_available = true
AND pg_try_advisory_xact_lock(id) )
LIMIT 1
FOR UPDATE
) sub
WHERE s.id = sub.id
RETURNING sub.prize_id, sub.id"
)
Very much inspired by this related answer on dba.SE.
But here (Postgres pg_try_advisory_lock blocks all records) they say, if I'm not mistaken, that I should not use pg_try_advisory_lock()
inside the WHERE
clause because I would be calling it once per row in the entire set that gets scanned (as part of the filtering that occurs in the where clause).
I just want my query to find and update the first (randomly, with LIMIT
) row where available = true
and update it to available = false
, and I need to lock the row while doing this, but without making new requests waiting for the release of the previous lock so I added advisory locks like suggested here.
Should I place pg_try_advisory_lock()
outside the WHERE
clause? How to do it?