Database

SQL JOIN 완벽 가이드: 실무 예제와 쿼리 최적화 팁

INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN 등 SQL JOIN의 모든 것을 실무 예제와 함께 정리합니다. 쿼리 성능, 실수 방지 체크리스트, FAQ까지 한 번에!

SQL JOIN 완벽 가이드

소개

SQL JOIN은 데이터베이스 실무에서 가장 자주 쓰는 문법이지만, 종류와 동작을 헷갈리면 잘못된 결과나 느린 쿼리가 나오기 쉽습니다. 우리도 리워드·이벤트 데이터를 다루면서 JOIN 실수와 성능 이슈를 여러 번 겪었고, 그때 정리한 “실무에서 바로 쓸 수 있는” 예제와 주의사항, 최적화 팁을 모아 두었습니다.


1. JOIN의 종류와 차이

JOIN 종류설명
INNER JOIN두 테이블 모두에 존재하는 데이터만 반환
LEFT (OUTER) JOIN왼쪽 테이블의 모든 데이터 + 매칭되는 오른쪽
RIGHT (OUTER) JOIN오른쪽 테이블의 모든 데이터 + 매칭되는 왼쪽
FULL OUTER JOIN양쪽 테이블의 모든 데이터(매칭 여부 무관)
CROSS JOIN두 테이블의 모든 조합(카티션 곱)

2. 실무 예제 테이블

sql
1-- 직원 테이블
2CREATE TABLE employees (
3  id INT PRIMARY KEY,
4  name VARCHAR(50),
5  dept_id INT
6);
7
8-- 부서 테이블
9CREATE TABLE departments (
10  id INT PRIMARY KEY,
11  dept_name VARCHAR(50)
12);
13
14-- 데이터 입력
15INSERT INTO employees VALUES 
16  (1, '홍길동', 10),
17  (2, '이영희', 20),
18  (3, '김철수', NULL);
19
20INSERT INTO departments VALUES 
21  (10, '개발'),
22  (20, '마케팅'),
23  (30, '영업');

3. JOIN별 실전 쿼리 & 결과

1) INNER JOIN

sql
1SELECT e.name, d.dept_name 
2FROM employees e 
3INNER JOIN departments d 
4  ON e.dept_id = d.id;

설명: 두 테이블 모두에 매칭되는 데이터만 반환

namedept_name
홍길동개발
이영희마케팅

2) LEFT JOIN

sql
1SELECT e.name, d.dept_name 
2FROM employees e 
3LEFT JOIN departments d 
4  ON e.dept_id = d.id;

설명: 직원 전체 + 부서가 없는 직원도 포함 (NULL)

namedept_name
홍길동개발
이영희마케팅
김철수NULL

3) RIGHT JOIN

sql
1SELECT e.name, d.dept_name 
2FROM employees e 
3RIGHT JOIN departments d 
4  ON e.dept_id = d.id;

설명: 부서 전체 + 소속 직원이 없는 부서도 포함 (NULL)

namedept_name
홍길동개발
이영희마케팅
NULL영업

4) FULL OUTER JOIN (DBMS 지원 시)

sql
1SELECT e.name, d.dept_name 
2FROM employees e 
3FULL OUTER JOIN departments d 
4  ON e.dept_id = d.id;

설명: 직원, 부서 모두 매칭 여부와 상관없이 전체 반환

namedept_name
홍길동개발
이영희마케팅
김철수NULL
NULL영업

5) CROSS JOIN

sql
1SELECT e.name, d.dept_name 
2FROM employees e 
3CROSS JOIN departments d;

설명: 모든 직원-부서 조합 (카티션 곱)

namedept_name
홍길동개발
홍길동마케팅
홍길동영업
이영희개발
이영희마케팅
이영희영업
김철수개발
김철수마케팅
김철수영업

4. 실무 체크리스트

💡 JOIN 쿼리 작성 시 반드시 확인해야 할 사항들입니다.

  • JOIN 조건(ON 절)을 빠뜨리지 않았는가?
  • NULL 값 처리(LEFT/RIGHT JOIN 결과) 방안을 마련했는가?
  • 불필요한 CROSS JOIN을 사용하지 않았는가?
  • 조인 대상 컬럼에 인덱스가 있는가?
  • 결과 데이터가 예상과 일치하는지 쿼리 결과를 검증했는가?

5. 실무 주의사항 & 실패사례

⚠️ 실제 프로젝트에서 자주 발생하는 문제점들입니다.

주의사항

  • ON 조건 없이 JOIN을 사용해, 의도치 않은 카티션 곱(수십만~수백만 건)이 발생한 사례가 많습니다.
  • LEFT JOIN 결과의 NULL을 제대로 처리하지 않아, 통계/리포트에서 누락/오류가 발생할 수 있습니다.
  • 대용량 테이블 조인 시 인덱스가 없으면 쿼리 속도가 급격히 저하됩니다.
  • DBMS마다 FULL OUTER JOIN 지원 여부가 다르니, 미지원 시 UNION 등으로 대체해야 합니다.

성능 최적화 팁

  • 조인 컬럼에 인덱스 추가
  • 불필요한 컬럼 제외
  • 서브쿼리 대신 CTE 사용
  • 적절한 조인 순서 선택

6. 자주 묻는 질문(FAQ)

Q. LEFT JOIN과 RIGHT JOIN, 언제 써야 하나요?

💡 둘 다 결과는 비슷하지만, 기준이 되는(모든 행을 포함할) 테이블이 왼쪽이면 LEFT, 오른쪽이면 RIGHT를 사용합니다.

Q. FULL OUTER JOIN이 없는 DB에서는 어떻게 하나요?

sql
1SELECT e.name, d.dept_name 
2FROM employees e 
3LEFT JOIN departments d 
4  ON e.dept_id = d.id
5UNION
6SELECT e.name, d.dept_name 
7FROM employees e 
8RIGHT JOIN departments d 
9  ON e.dept_id = d.id;

Q. JOIN이 느릴 때 어떻게 최적화하나요?

💡 성능 최적화를 위한 핵심 전략

  • 조인 컬럼에 인덱스를 추가하고
  • 불필요한 컬럼/행은 쿼리에서 제외하세요
  • 서브쿼리 대신 WITH절(CTE)도 활용해보세요

실전 성능 최적화 팁

인덱스 활용

sql
1-- JOIN 조건에 사용되는 컬럼에 인덱스 생성
2CREATE INDEX idx_employees_dept_id ON employees(dept_id);
3CREATE INDEX idx_orders_user_id ON orders(user_id);
4
5-- 복합 인덱스 (WHERE와 JOIN 조건 모두 고려)
6CREATE INDEX idx_orders_user_status ON orders(user_id, status);

EXPLAIN으로 쿼리 분석

sql
1-- 쿼리 실행 계획 확인
2EXPLAIN ANALYZE
3SELECT e.name, d.dept_name
4FROM employees e
5INNER JOIN departments d ON e.dept_id = d.id
6WHERE e.salary > 50000;

서브쿼리 vs JOIN

sql
1-- 나쁜 예: 서브쿼리 사용
2SELECT name
3FROM employees
4WHERE dept_id IN (
5  SELECT id FROM departments WHERE dept_name = 'Engineering'
6);
7
8-- 좋은 예: JOIN 사용 (일반적으로 더 빠름)
9SELECT e.name
10FROM employees e
11INNER JOIN departments d ON e.dept_id = d.id
12WHERE d.dept_name = 'Engineering';

실무 체크리스트

JOIN을 사용할 때 다음 사항을 확인하세요:

  • JOIN 조건에 인덱스가 있는가?
  • NULL 값 처리가 올바른가?
  • 중복 데이터가 발생하지 않는가?
  • 필요한 데이터만 SELECT하고 있는가?
  • WHERE 조건이 JOIN 전에 적용되는가?
  • 쿼리 실행 계획을 확인했는가?

7. 참고자료

📚 더 깊이 학습하기 위한 추천 자료

공유하기

관련 포스트