MySQL 에서 조인을 사용할 때

Min
4 min readJun 23, 2021

RealMySQL 을 읽고 정리한 내용입니다.

MySQL 조인

  • 조인에서 어느 테이블을 먼저 읽을지 결정하는게 매우 중요함.
  • inner join 은 어느 테이블을 먼저 읽던 결과가 동일하므로 옵티마이저가 다양하게 최적화 가능.
  • outer join 은 반드시 outer 가 되는 테이블을 먼저 읽어야 하기 때문에 조인 순서를 옵티마이저가 선택할 수 없음

outer join 사용시 주의점

outer join 에서 레코드가 없을 수도 있는 쪽의 테이블에 대한 조건은 반드시 LEFT JOIN 의 ON 절에 명시해야함. 그렇지 않으면 옵티마이저는 OUTER JOIN 을 내부적으로 INNER JOIN 으로 변형시켜서 처리해 버릴 수도 있음.

-- 내부적으로 inner 조인으로 변경함
select *
from employees e
left outer join salaries s on e.emp_no = s.emp_no
where s.salary > 5000;
-- 이렇게 수정할 것
select *
from employees e
left outer join salaries s on e.emp_no = s.emp_no and s.salary > 5000;

카테시안 조인

FULL JOIN, CROSS JOIN 이라고도 한다. 조인 조건 없이 조인에 참여한 N 개의 테이블에 모든 레코드 조합을 결과로 가져온다. (아주 위험)

MySQL 에서 CROSS JOIN 은 카테시안 조인이 될 수도 있고, 아닐 수도 있다함. 조건이 적절히 있으면 inner join 으로 처리, 없다면 카테시안 조인이 된다.

-- 두 쿼리 결과가 같다. (모두 inner join 처리됨)select *
from dept_emp d
inner join employees e on d.emp_no = e.emp_no;

select *
from dept_emp d
cross join employees e on d.emp_no = e.emp_no;

single-sweep multi join

MySQL 의 nested-loop 조인을 “single-sweep multi join” 이라고 표현하기도 한다.

위의 쿼리는 3개의 테이블을 조인하고 있고, 실행결과는 d 테이블 읽고, de 테이블 읽고, e 테이블이 읽혔다는 걸 알 수 있다.

반복 루프를 돌면서 레코드 단위로 모든 조인 대상 테이블을 차례대로 읽는 방식을 “single-sweep multi join” 이라고 하고, MySQL 조인 결과는 드라이빙 테이블을 읽은 순서대로 레코드가 정렬된다, 드리븐 테이블들은 단순히 드라이빙 테이블의 레코드를 읽는 순서대로 검색만 된다.

조인 버퍼를 이용한 조인 (Using join buffer)

드라이빙 테이블과 드리븐 테이블 사이에 조인 조건이 없다면, 드리븐 테이블은 여러번 테이블 풀 스캔을 하게 된다. 만약 어떤 방식으로도 드리븐 테이블의 풀 스캔을 피할 수 없다면 옵티마이저는 드라이빙 테이블에서 읽은 레코드를 메모리에 캐시하고 드리븐 테이블과 이 메모리 캐시를 조인하는 형태로 처리 한다. (join_buffer_size 라는 변수로 버퍼 크기 제한 가능)

조인 버퍼가 사용되는 조인에서는 조인의 결과 순서가 흐트러질 수 있다.

조인 관련 주의 사항

  1. 정렬 결과를 인덱스와 실행 결괴에 의존하지 말고, 명식적으로 ORDER BY 절을 추가하자. 쿼리의 실행 결과는 언제 든지 변경될 수 있기 때문이다.
  2. INNER JOIN 과 OUTER JOIN 을 선택해야 할 때 성능을 고려해서 선택하지 말고, 업무 요건에 따라 선택하는 것이 바람직하다. 실제 가져와야 하는 레코드가 같으면 쿼리의 성능은 비슷하다.

--

--