Voláte pg_try_advisory_lock() jednou na řádek v celé sadě, která je skenována (jako součást filtrování, ke kterému dochází v where
klauzule), zatímco chcete, aby byla volána pouze jednou na řádek v tabulce1 vrácené dotazem.
Místo toho můžete zkusit použít poddotaz nebo 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);
Nespoléhejte se však ani na to, že to bude nutně fungovat podle očekávání:Postgres by měl být v pokušení přepsat to tak, jak byl váš původní dotaz.
Další možností je tato, protože select
část příkazu je v dotazu vyhodnocena velmi pozdě:
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;
Skutečným problémem v praxi je, že pg_try_advisory_lock()
je něco, co byste normálně našli v aplikaci nebo ve funkci, spíše než v dotazu, jako to děláte vy. Když už o tom mluvíme, v závislosti na tom, co děláte, jste si jisti, že byste neměli používat select … for update
?
Ohledně vaší aktualizace:
Ano. Kvůli limit 1
, najde shodu a okamžitě se zastaví. Pravděpodobně se však děje to, že nevyhodnocuje where
klauzule ve stejném pořadí v závislosti na vašich dotazech. SQL neposkytuje žádnou záruku, že a <> 0
část v a <> 0 and b / a > c
se hodnotí jako první. Pokud se použije na váš případ, nenabízí žádnou záruku, že bude poradní zámek získán po řada z a je spojena s b.