본문 바로가기

경험과 지식

에러 FOR UPDATE cannot be applied to the nullable side of an outer join(postgres)

동시성 제어를 위해 select ... left join ... for update를 사용하여 배타 락을 획득할 때 다음과 같은 에러를 만났습니다.
"FOR UPDATE cannot be applied to the nullable side of an outer join"

 

실행하려 했던 SQL은 대략 아래와 같습니다.

SELECT *
FROM   member
       LEFT JOIN team
              ON member.team_id = team.team_id
FOR UPDATE;

 

한 트랜잭션A에서 위 SQL이 실행될 때 team이 조인이 되지 않아서 null 상태로 읽었다고 가정해 보겠습니다.

결과 셋은 아래와 같습니다.

 

이 트랜잭션이 커밋되기 전에 다른 트랜잭션 B로부터 team_id : 1이 삽입되었다면, team_id 1은 락에 걸려야 할지 안걸려야 할 지 모호합니다. 이러한 일관성의 문제 등의 이유로 left join을 비롯한 outer join 은 for update 가 불가합니다.

 

해결방법은 2가지가 있습니다.

 

1. inner join

조인이 수행된 team 테이블의 레코드라도 잠그고 싶다면, inner join을 통해 해결할 수 있습니다.

SELECT *
FROM   member
       INNER JOIN team
              ON member.team_id = team.team_id
FOR UPDATE;

 

 

2. for update of 테이블명

outer join 된 결과 셋이 더 중요하다면 of 옵션으로 명시된 테이블의 락만 획득할 수 있습니다.

이 경우 team 레코드가 조인되었어도 잠그지 않습니다.

물론 postgres REAPEATABLE READ 이상의 격리 수준에서는 NON_REPEATABLE READ 나 팬텀 리드 현상이 없기 때문에 트랜잭션 내에서 team 관련 결과 셋이 바뀔 일은 없습니다.

SELECT *
FROM   member
       LEFT JOIN team
              ON member.team_id = team.team_id
FOR UPDATE OF member;