2012-04-20 5 views
19

PostgreSQL 교착 상태에 대해 조금 혼란 스럽습니다.업데이트를 실행할 때 PostgreSQL의 교착 상태가 발생했습니다.

전형적인 교착 상태의 예입니다 : 내가 코드를 변경

-- Transaction 1 
UPDATE customer SET ... WHERE id = 1 
UPDATE customer SET ... WHERE id = 2 

-- Transaction 2 
UPDATE customer SET ... WHERE id = 2 
UPDATE customer SET ... WHERE id = 1 

하지만 경우에 다음과 같이

-- Transaction 1 
UPDATE customer SET ... WHERE id IN (1, 2) 

-- Transaction 2 
UPDATE customer SET ... WHERE id IN (1, 2) 

여기 교착 상태의 가능성이 될 것인가?

본질적으로 내 질문은 : 두 번째 경우에 PostgreSQL은 행을 하나씩 잠 그거나 WHERE 조건에서 다루는 전체 범위를 잠급니다?

미리 감사드립니다.

답변

28

PostgreSQL에서 행은 업데이트 될 때 잠길 것입니다. 사실이 방법이 실제로 작동하는 방식은 각 터플 (행 버전)이 xmin이라는 시스템 필드를 가지고있어서 해당 튜플을 현재 트랜잭션으로 변경했음을 나타냅니다 삽입 또는 갱신에 의한) 및 xmax 시스템 필드를 사용하여 (갱신 또는 삭제에 의해) 해당 트랜잭션의 만료 된 트랜잭션을 나타낼 수 있습니다. 데이터에 액세스 할 때, 액티브 "스냅 샷"을이 값과 대조하여 트랜잭션에서 볼 수 있는지 여부를 결정하기 위해 각 튜플을 검사합니다.

UPDATE를 실행하고 검색 조건과 일치하는 튜플의 스냅 샷과 활성 트랜잭션의 xmax를 볼 수있는 xmin이 있으면 해당 트랜잭션이 완료 될 때까지 블록되어 차단됩니다. 튜플을 처음 업데이트 한 트랜잭션이 롤백되면 트랜잭션이 활성화되어 행을 처리합니다. 첫 번째 트랜잭션이 커밋되면 트랜잭션이 활성화되어 현재 트랜잭션 격리 수준에 따라 조치를 취합니다.

분명히 교착 상태는 다른 순서로 행에 대한 결과입니다. RAM에는 행 레벨 잠금이 없으며 동시에 모든 행에 대해 얻을 수 있지만 행이 같은 순서로 업데이트되는 경우 순환 잠금을 사용할 수 없습니다. 아쉽게도 제안 된 IN(1, 2) 구문은이를 보장하지 않습니다. 다른 세션은 다른 원가 계산 요소를 활성화 할 수 있습니다. 백그라운드 "분석"작업은 하나의 계획과 다른 계획의 생성 사이에서 테이블에 대한 통계를 변경하거나 seqscan을 사용하고 새로운 seqscan을 유발하는 PostgreSQL 최적화의 영향을받을 수 있습니다 이미 진행중인 디스크에 합류하고 디스크 I/O를 줄이기 위해 "루프 처리"합니다.

응용 프로그램 코드 나 커서를 사용하여 한 번에 하나씩 업데이트를 수행하면 교착 상태가 아닌 단순한 차단 만 수행됩니다. 그러나 관계형 데이터베이스는 일반적으로 직렬화 실패가 발생하기 쉽기 때문에 SQLSTATE를 기반으로 트랜잭션을 인식하고 처음부터 전체 트랜잭션을 자동으로 재 시도하는 프레임 워크를 통해 관계형 데이터베이스에 액세스하는 것이 가장 좋습니다. PostgreSQL에서 직렬화 실패는 항상 40001 또는 40P01의 SQLSTATE를가집니다.

http://www.postgresql.org/docs/current/interactive/mvcc-intro.html

+0

고마워요! 위의 예는 교착 상태가 발생할 수 있습니다. 두 트랜잭션에서 행이 처리되는 순서를 모르기 때문에 교착 상태가 발생할 수 있습니다. – vyakhir

+0

드물지만 교착 상태가 발생할 수 있습니다. 첫 번째 예제 (명시 적으로 다른 주문 선택)와는 대조적으로 일반적인 경우가 있습니다. 테이블을 갱신하는 모든 트랜잭션의 지속 기간 동안 적절한 강도의 테이블 레벨 잠금을 취함으로써 교착 상태를 제외 할 수 있지만 치료가 질병보다 더 나을 수 있습니다. 자세한 내용은 내가 참조한 문서 섹션을 참조하십시오. – kgrittn

+0

그러나 행이 업데이트되었지만 전체 UPDATE 문이 아직 완료되지 않은 후에 PostgreSQL 릴리스 잠금이 작동합니까? 즉, 우리가 과 같은 성명을 가지고 있다면 UPDATE ... 어디에서 id (1, 2, 3, 5) postgresql 업데이트 후, ID = 1 행과 id = 2, 행 id = 1을 해제하겠습니까? 그렇다면 필요한 경우 어떻게 행을 롤백 할 것입니까? – vyakhir

관련 문제