LEFT (OUTER) JOIN 할때 결과 중복 이슈
문제 상황
매출 대시보드 작업 중 매출액이 2배 이상 으로 높게 잡히는 문제가 발생했다!
처음에는 매출데이터를 여러번 집어넣게 된 것은 아닌지 의심을 했다.
팀원 분들 도 여러 의견을 주셨는데,
매출데이터를 넣기전에 해당 날짜의 매출데이터가 이미 저장되어있는지 한번 확인을 하는데
호출이 여러번 되면서 동시성 문제가 생기게 되어 중복 체크가 제대로 되지 않은 것은 아닌지 등 여러 의견을 주셨다.
하루에 한번 업로드 하기 때문에
매출 데이터 업로드 로그를 확인해보았는데, 절대로 여러번 업로드가 일어나지 않았고,
실제 업로드 된 데이터도 발생 데이터 갯수 만큼 잘 업로드가 되어있었다.
원본 데이터는 제대로인데 어째서 계산 결과가 엄청 뛰게 된걸까?
원인 분석
매출데이터를 한번 조인 해서 뷰테이블을 만든 후 그 뷰테이블로 데이터를 그리는데 거기서 문제가 생긴 것이였다.
LEFT (OUTER) JOIN 할때 왼쪽 테이블에만 집중하는 경우,
예상치 못한 결과 가 생길 수 있다. 😱
LEFT OUTER JOIN(= LEFT JOIN)은
왼쪽 테이블 기준으로 오른쪽 테이블상에 연결된 정보가 있으면 컬럼을 가져오고 없으면 NULL로 채워준다.
그런데 오른쪽 테이블에 연결 정보가 중복으로 있을 경우
결과 테이블의 카디널리티가 늘어날 수 있다.
1. 일반적인 경우
SELECT * FROM A
LEFT JOIN B
ON A.id = B.id;
2. 오른쪽 테이블에 연결 정보 중복이 있을 경우
SELECT * FROM A
LEFT JOIN B
ON A.id = B.id;
중복이 없도록 테이블 설계를 잘 하는 것이 우선이겠지만,
중복이 이미 생겨버렸고, 제거 하기도 힘든 상황이라면
GROUP BY 를 통해 연결하려는 오른쪽 정보의 연결정보당 row 하나씩만 남기도록 해야한다.
해결
GROUP BY 후 JOIN 수행
SELECT * FROM A
LEFT JOIN (
SELECT
id,
MAX(grade)
FROM B
GROUP BY B.id
) AS B
ON A.id = B.id;
TIP. 쿼리 플레이그라운드 사이트