Du ringer til pg_try_advisory_lock() én gang pr. række i hele sættet, der bliver scannet (som en del af den filtrering, der forekommer i where
klausul), mens du kun vil have det kaldt én gang pr. række i tabel1 returneret af forespørgslen.
Du kan prøve at bruge en underforespørgsel eller en CTE i stedet:
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);
Men stol heller ikke på, at det nødvendigvis fungerer som forventet:Postgres burde være fristet til at omskrive det, som din oprindelige forespørgsel var.
En anden mulighed er dette, da select
en del af en erklæring evalueres meget sent i forespørgslen:
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;
Det virkelige problem i praksis er, at pg_try_advisory_lock()
er noget, du normalt ville finde i app-land eller i en funktion, snarere end i en forespørgsel, som du laver. Apropos hvilket, afhængigt af hvad du laver, er du sikker på, at du ikke skal bruge select … for update
?
Angående din opdatering:
Ja. På grund af limit 1
, det kommer til at finde et match og stoppe med det samme. Hvad der dog sandsynligvis sker, er, at det ikke evaluerer where
klausul i samme rækkefølge afhængigt af dine forespørgsler. SQL giver ingen garanti for, at a <> 0
del i a <> 0 and b / a > c
bliver evalueret først. Anvendt på dit tilfælde giver det ingen garanti for, at den rådgivende lås er opnået efter rækken fra a er sammenføjet med b.