Wywołujesz pg_try_advisory_lock() raz na wiersz w całym zestawie, który jest skanowany (w ramach filtrowania, które występuje w where klauzula), podczas gdy chcesz, aby była wywoływana tylko raz na wiersz w tabeli 1 zwróconej przez zapytanie.
Zamiast tego możesz spróbować użyć podzapytania lub 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);
Ale nie należy polegać na tym, aby koniecznie działać zgodnie z oczekiwaniami:Postgres powinien ulec pokusie, aby przepisać go tak, jak początkowe zapytanie.
Inna możliwość jest taka, ponieważ select część instrukcji jest oceniana bardzo późno w zapytaniu:
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;
Prawdziwym problemem w praktyce jest to, że pg_try_advisory_lock() jest czymś, co zwykle można znaleźć w aplikacji lub w funkcji, a nie w zapytaniu, jak to robisz. Skoro o tym mowa, w zależności od tego, co robisz, na pewno nie powinieneś używać select … for update ?
Jeśli chodzi o twoją aktualizację:
TAk. Ze względu na limit 1 , znajdzie dopasowanie i natychmiast się zatrzyma. Prawdopodobnie jednak dzieje się tak, że nie ocenia where klauzula w tej samej kolejności w zależności od zapytań. SQL nie gwarantuje, że a <> 0 część w a <> 0 and b / a > c jest oceniany jako pierwszy. Zastosowany w Twoim przypadku nie gwarantuje, że blokada doradcza zostanie uzyskana po wiersz od a jest połączony z b.