2013-11-21 2 views
4

저는 Postgres에서 pg_try_advisory_lock()을 사용하고 있습니다.Postgres pg_try_advisory_lock 모든 레코드를 차단합니다

다음 두 쿼리는 table1 하나 개 이상의 레코드를 잠금 :

1)

SELECT a.id 
FROM table1 a 
JOIN table2 b ON a.table1_id = b.id 
WHERE 
    table2.id = 1 
    AND 
    pg_try_advisory_lock('table1'::regclass::integer, a.id) 
LIMIT 1; 

하지만

SELECT a.id 
FROM table1 a 
JOIN table2 b ON a.table1_id = b.id 
WHERE table2.id = 1 

반환 한 기록을.

2)

SELECT a.id 
FROM table1 a 
JOIN table2 b ON a.table1_id = b.id 
JOIN table3 c ON b.table2_id = c.id 
WHERE 
    table3.id = 1 
    AND 
    pg_try_advisory_lock('table1'::regclass::integer, a.id) 
LIMIT 1; 

그러나 나는 단지 하나의 레코드를 잠글 pg_try_advisory_lock()이 필요합니다.

무엇이 잘못 되었나요?

UPD

그러나 이상한 것은입니다 나는 다음과 같은 쿼리를

SELECT a.id 
FROM table1 a 
JOIN table2 b ON a.table1_id = b.id 
WHERE 
    pg_try_advisory_lock('table1'::regclass::integer, a.id) 
LIMIT 1; 

포스트 그레스 잠금 하나의 행을 실행할 때. 그래서 Postgres는 맨 처음 행을 스캔 한 다음 멈 춥니 다. 나는 그것을 얻지 못한다 : 모든 행을 스캔 한 다음 결과를 한 행으로 제한해야 하는가, 그렇지 않은가?

답변

5

where 절에서 발생하는 필터링의 일부로 스캔 된 전체 집합에서 pg_try_advisory_lock()을 한 번 호출하는 반면 쿼리에서 반환 한 table1의 행당 한 번만 호출하면됩니다. .

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); 

를하지만 중 예상대로 반드시 일이에 의존하지 않는 :

당신은 하위 쿼리 또는 대신 CTE를 사용하여 시도해 볼 수도 있습니다 포스트 그레스는 귀하의 초기 쿼리가했던 방법을 다시 유혹한다.

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; 

실제로 진짜 문제는 pg_try_advisory_lock() 당신은 일반적으로 응용 프로그램의 토지에서 찾을 것입니다 무언가이다 : 성명의 select 부분이 매우 늦게 쿼리에서 평가되기 때문에

또 다른 가능성은, 이것이다 당신이하는 것처럼 쿼리에서보다는 함수에서. 말하자면, 당신이하는 일에 따라 select … for update을 사용하지 않아야합니까? 당신의 갱신에 관한


:

포스트 그레스는 첫 번째 행이 다음 중지 스캔?

예. limit 1으로 인해 일치 항목을 찾아 즉시 중지합니다. 그러나 아마도 쿼리에 따라 같은 순서로 where 절을 평가하지 않을 수도 있습니다. SQL은 a <> 0 and b/a > ca <> 0 부분이 먼저 평가된다는 보장을하지 않습니다.귀하의 경우에 적용하면 뒤에 자문 잠금이 확보되었다고 보장 할 수 없으며, a의 행은 b와 결합됩니다.

+0

다른 스크립트가 다른 레코드를 찾아야하기 때문에 선택 ...을 업데이트 할 필요가 없습니다. – fdoo4un

+0

난 여전히 당신이 응용 프로그램 - 토지보다는 SQL - 땅에 잠겨 있어야한다고 생각합니다. –

+0

CTE가 효과적입니다. 충고에 감사하다! 또한 질문을 업데이트했습니다. plz를 참조하십시오. – fdoo4un

관련 문제