Je roept pg_try_advisory_lock() één keer per rij aan in de hele set die wordt gescand (als onderdeel van de filtering die plaatsvindt in de where
clausule), terwijl u wilt dat deze slechts één keer wordt aangeroepen per rij in tabel1 die door de query wordt geretourneerd.
U kunt in plaats daarvan proberen een subquery of een CTE te gebruiken:
with rows as (
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
)
select rows.*
from rows
where pg_try_advisory_lock('table1'::regclass::integer, rows.id);
Maar vertrouw er ook niet op dat het noodzakelijkerwijs werkt zoals verwacht:Postgres zou in de verleiding moeten komen om het te herschrijven zoals uw eerste vraag was.
Een andere mogelijkheid is dit, aangezien de select
een deel van een instructie wordt zeer laat in de query geëvalueerd:
with rows as (
SELECT a.id,
pg_try_advisory_lock('table1'::regclass::integer, a.id) as locked
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
)
select rows.id
from rows
where rows.locked;
Het echte probleem in de praktijk is dat pg_try_advisory_lock()
is iets dat je normaal gesproken zou vinden in app-land of in een functie, in plaats van in een zoekopdracht zoals je doet. Daarover gesproken, afhankelijk van wat je doet, weet je zeker dat je select … for update
niet moet gebruiken ?
Wat betreft je update:
Ja. Vanwege de limit 1
, het gaat een match vinden en onmiddellijk stoppen. Wat er waarschijnlijk gebeurt, is echter dat het de where
. niet evalueert clausule in dezelfde volgorde, afhankelijk van uw vragen. SQL biedt geen garantie dat de a <> 0
deel in a <> 0 and b / a > c
wordt als eerste beoordeeld. Toegepast op uw geval, biedt het geen garantie dat de adviesvergrendeling na . wordt verkregen de rij uit a wordt samengevoegd met b.