Du anropar pg_try_advisory_lock() en gång per rad i hela uppsättningen som skannas (som en del av filtreringen som sker i where
klausul), medan du bara vill att den ska anropas en gång per rad i tabell1 returneras av frågan.
Du kan försöka använda en underfråga eller en CTE istället:
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 lita inte på att det nödvändigtvis fungerar som förväntat heller:Postgres bör frestas att skriva om det som din ursprungliga fråga var.
En annan möjlighet är detta, eftersom select
en del av ett uttalande utvärderas mycket sent i frågan:
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 verkliga problemet i praktiken är att pg_try_advisory_lock()
är något du normalt hittar i appland eller i en funktion, snarare än i en fråga som du gör. På tal om vilket, beroende på vad du gör, är du säker på att du inte ska använda select … for update
?
Angående din uppdatering:
Ja. På grund av limit 1
, det kommer att hitta en match och omedelbart sluta. Vad som förmodligen händer är dock att det inte utvärderar where
klausul i samma ordning beroende på dina frågor. SQL erbjuder ingen garanti för att a <> 0
del i a <> 0 and b / a > c
utvärderas först. Tillämpat på ditt fall ger det ingen garanti att det rådgivande låset erhålls efter raden från a är sammanfogad med b.