PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Postgres pg_try_advisory_lock blocca tutti i record

Stai chiamando pg_try_advisory_lock() una volta per riga nell'intero set che viene scansionato (come parte del filtro che si verifica nel where clausola), mentre vuoi che venga chiamato solo una volta per riga nella tabella1 restituita dalla query.

Potresti invece provare a utilizzare una sottoquery o un 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);

Ma non fare affidamento su questo per funzionare necessariamente come previsto:Postgres dovrebbe essere tentato di riscriverlo come era la tua richiesta iniziale.

Un'altra possibilità è questa, poiché select parte di un'istruzione viene valutata molto tardi nella query:

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;

Il vero problema in pratica è che pg_try_advisory_lock() è qualcosa che normalmente troverai in app land o in una funzione, piuttosto che in una query come stai facendo. A proposito, a seconda di cosa stai facendo, sei sicuro che non dovresti usare select … for update ?

Per quanto riguarda il tuo aggiornamento:

Sì. A causa del limit 1 , troverà una corrispondenza e si fermerà immediatamente. Quello che probabilmente sta succedendo, però, è che non sta valutando il where clausola nello stesso ordine a seconda delle vostre domande. SQL non offre alcuna garanzia che a <> 0 parte in a <> 0 and b / a > c viene valutato per primo. Applicato al tuo caso, non offre alcuna garanzia che il blocco di avviso venga ottenuto dopo la riga da a viene unita con b.