Извиквате pg_try_advisory_lock() веднъж на ред в целия набор, който се сканира (като част от филтрирането, което се случва в where
клауза), докато искате да се извиква само веднъж на ред в таблица1, върната от заявката.
Можете да опитате да използвате подзаявка или CTE вместо това:
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);
Но не разчитайте и на това, че непременно ще работи според очакванията:Postgres трябва да се изкуши да го пренапише по начина, по който беше първоначалната ви заявка.
Друга възможност е това, тъй като select
част от израз се оценява много късно в заявката:
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;
Истинският проблем на практика е, че pg_try_advisory_lock()
е нещо, което обикновено бихте намерили в областта на приложението или във функция, а не в заявка, както правите. Говорейки за това, в зависимост от това, което правите, сигурни ли сте, че не трябва да използвате select … for update
?
Относно вашата актуализация:
да Поради limit 1
, ще намери съвпадение и веднага ще спре. Това, което вероятно се случва обаче, е, че не се оценява where
клауза в същия ред в зависимост от вашите заявки. SQL не предлага гаранция, че a <> 0
част в a <> 0 and b / a > c
първо се оценява. Приложено към вашия случай, то не предлага гаранция, че препоръчителното заключване е получено след редът от a се свързва с b.