Anda memanggil pg_try_advisory_lock() sekali per baris di seluruh rangkaian yang dipindai (sebagai bagian dari pemfilteran yang terjadi di where
klausa), sedangkan Anda hanya ingin memanggilnya satu kali per baris dalam tabel1 yang dikembalikan oleh kueri.
Anda dapat mencoba menggunakan subquery atau CTE sebagai gantinya:
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);
Tapi jangan mengandalkan itu untuk selalu berfungsi seperti yang diharapkan:Postgres harus tergoda untuk menulis ulang seperti kueri awal Anda.
Kemungkinan lain adalah ini, karena select
bagian dari pernyataan dievaluasi sangat terlambat dalam kueri:
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;
Masalah sebenarnya dalam praktiknya adalah pg_try_advisory_lock()
adalah sesuatu yang biasanya Anda temukan di app land atau dalam suatu fungsi, bukan dalam kueri seperti yang Anda lakukan. Omong-omong, tergantung pada apa yang Anda lakukan, apakah Anda yakin tidak boleh menggunakan select … for update
?
Mengenai pembaruan Anda:
Ya. Karena limit 1
, itu akan menemukan kecocokan dan segera berhenti. Apa yang mungkin terjadi, bagaimanapun, adalah bahwa itu tidak mengevaluasi where
klausa dalam urutan yang sama tergantung pada pertanyaan Anda. SQL tidak memberikan jaminan bahwa a <> 0
bagian dalam a <> 0 and b / a > c
akan dievaluasi terlebih dahulu. Diterapkan pada kasing Anda, tidak ada jaminan bahwa kunci penasehat diperoleh setelah baris dari a bergabung dengan b.