sql >> Databáze >  >> RDS >> PostgreSQL

Postgres pg_try_advisory_lock blokuje všechny záznamy

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.




  1. Rychlé nasazení aplikace Visual Studio 2010 s databází SQL

  2. Jak změnit max_connections pro Postgres pomocí příkazu SQL

  3. CHYBA:musí být členem role Při vytváření schématu v PostgreSQL

  4. Přejmenujte tabulku v MySQL