PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Postgres pg_try_advisory_lock bloqueia todos os registros


Você está chamando pg_try_advisory_lock() uma vez por linha em todo o conjunto que é verificado (como parte da filtragem que ocorre no where cláusula), enquanto você deseja que ela seja chamada apenas uma vez por linha na tabela1 retornada pela consulta.

Você pode tentar usar uma subconsulta ou um 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);

Mas também não confie nisso para funcionar necessariamente como esperado:o Postgres deve ser tentado a reescrevê-lo da maneira que sua consulta inicial foi.

Outra possibilidade é esta, pois o select parte de uma instrução é avaliada muito tarde na consulta:
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;

O verdadeiro problema na prática é que pg_try_advisory_lock() é algo que você normalmente encontraria na área do aplicativo ou em uma função, em vez de em uma consulta como você está fazendo. Falando nisso, dependendo do que você está fazendo, você tem certeza que não deveria estar usando select … for update ?

Sobre sua atualização:

Sim. Devido ao limit 1 , ele encontrará uma correspondência e parará imediatamente. O que provavelmente está acontecendo, porém, é que não está avaliando o where cláusula na mesma ordem, dependendo de suas consultas. O SQL não oferece garantia de que o a <> 0 parte em a <> 0 and b / a > c é avaliado primeiro. Aplicado ao seu caso, não oferece garantia de que o bloqueio consultivo seja obtido depois a linha de a é unida a b.