본문 바로가기
Language & Tool/sql

🗄️주요 JOIN의 종류 완벽 정리(Inner, Left, Cross, Self 등)

by 박수무당벌레 2026. 7. 2.

1. 조인(JOIN)이란?

  • 개념: 둘 이상의 데이터베이스 테이블을 연결하여 데이터를 하나의 '결과 집합'으로 결합하는 연산.
  • 역할: 여기저기 분산된 데이터를 조건에 맞춰 다시 합쳐서 볼 수 있도록 함.
  • 특징
    • RDB의 핵심 (정규화와의 관계): 관계형 데이터베이스(RDB)는 중복을 피하고 데이터를 효율적으로 관리하기 위해 테이블을 나누어 저장하는데, 이를 정규화라고 한다. JOIN은 이렇게 나눠서 저장된 데이터를 다시 합쳐서 보기 위해 반드시 필요함.
    • 관계(Relationship) 중심: 무작위로 합치는 것이 아니라, 테이블 간에 공유하는 공통 열(예: 회원 ID, 부서 번호 등)을 기준으로 매칭되어 결합한다.

2. 대표적인 JOIN의 종류

① INNER JOIN (내부 조인)

  • 개념: 양쪽 테이블 모두에 공통으로 존재하는 데이터만 매칭해서 결합 후 가져온다.
  • 특징: 어느 한쪽에만 있는 데이터는 결과에서 제외된다. (교집합)
  • 조인 절(어구): INNER JOIN 또는 JOIN (INNER는 생략 가능)
  • 예시: 주문 테이블과 고객 테이블을 JOIN할 때, 주문을 한 적이 있는 고객의 정보만 매칭되어 나옴
SELECT * FROM Users U
INNER JOIN Orders O ON U.user_id = O.user_id;

② LEFT JOIN (왼쪽 외부 조인)

  • 개념: 왼쪽(기준) 테이블의 모든 데이터를 가져오고, 오른쪽 테이블에서는 매칭되는 데이터만 가져온다.
  • 특징: 만약 오른쪽 테이블에 매칭되는 데이터가 없다면, 그 자리는 NULL로 채워짐. 
  • 조인 절(어구): LEFT JOIN 또는 LEFT OUTER JOIN
  • 예시: 가입한 전체 고객 명단을 보여주되, 주문 내역이 있는 고객은 주문 정보까지 보여주고 주문한 적이 없는 고객은 주문 칸을 비워준다(NULL). (회원 가입은 했지만 주문 이력이 없는 회원을 찾을 때 유용)
SELECT * FROM Users U
LEFT JOIN Orders O ON U.user_id = O.user_id;
💡배치되는 위치에 따른 조인 기준
(선)FROM A: 왼쪽에 배치 (LEFT JOIN에서는 기준)
(후)[다른 조인 종류] JOIN B: 오른쪽에 배치

③ RIGHT JOIN (오른쪽 외부 조인)

  • 개념: LEFT JOIN과 반대로 오른쪽(기준) 테이블의 모든 데이터를 가져오고, 왼쪽 테이블에서 매칭되는 데이터를 가져온다.
  • 특징: 매칭되지 않는 왼쪽 테이블의 자리는 NULL이 된다.
    • 보통 테이블 위치만 바꾸어 LEFT JOIN으로 많이 대체한다. (왼쪽에서 오른쪽으로 읽는게 편해서)
  • 조인 절(어구): RIGHT JOIN 또는 RIGHT OUTER JOIN
SELECT 사원.이름, 부서.부서명
FROM 사원 RIGHT OUTER JOIN 부서
ON 사원.부서번호 = 부서.부서번호;
더보기

💻 결과 예시

 

사원 이름 (왼쪽) 부서 이름 (오른쪽)
김철수 인사부
이영희 개발부
NULL (텅 비어있음) 마케팅부

④ FULL JOIN (전체 외부 조인)

  • 개념: 양쪽 테이블의 모든 데이터를 가져온다. (합집합)
  • 특징: 서로 매칭되는 데이터는 합쳐서 보여주고, 한쪽에만 있는 데이터는 반대쪽을 NULL로 채워 모두 출력한다.
  • 조인 절(어구): FULL JOIN 또는 FULL OUTER JOIN
  • 💡 참고: MySQL은 FULL OUTER JOIN 문법을 직접 지원하지 않아, LEFT JOIN과 RIGHT JOIN을 UNION으로 합쳐서 구현해야 한다.
-- 1. 왼쪽 테이블(Users) 기준 전부 가져오기 (LEFT JOIN)
SELECT U.user_id, U.name, O.order_id, O.amount
FROM Users U
LEFT JOIN Orders O ON U.user_id = O.user_id

UNION -- 중복된 데이터는 제거하고 두 결과를 하나로 합치기!

-- 2. 오른쪽 테이블(Orders) 기준 전부 가져오기 (RIGHT JOIN)
SELECT U.user_id, U.name, O.order_id, O.amount
FROM Users U
RIGHT JOIN Orders O ON U.user_id = O.user_id;
더보기

💡 예시 코드 설명

  • 상단 LEFT JOIN 결과: 주문 내역이 없는 유저까지 포함한 전체 유저 목록이 나옴.
  • 하단 RIGHT JOIN 결과: 가입된 유저 정보가 없는 유령 주문(탈퇴한 회원 등)까지 포함한 전체 주문 목록이 나옴.
  • UNION 키워드: 이 두 결과를 위아래로 이어 붙이면서, 양쪽에 공통으로 존재하던 데이터(중복 행)는 알아서 한 줄만 남기고 깔끔하게 정리해 준다.
  • ⚠️ 주의할 점: UNION으로 두 쿼리를 합칠 때는 위쪽 SELECT 절에 적은 컬럼의 개수와 종류(U.user_id, U.name...)가 아래쪽 SELECT 절과 완벽히 일치해야 에러가 나지 않는다

📊 요약 정리 비교

  결과에 포함되는 데이터 매칭 실패 시 처리
INNER JOIN 양쪽 테이블에 공통으로 존재하는 행 (교집합) 결과에서 제외
LEFT JOIN 왼쪽 테이블 전체 + 오른쪽 테이블 매칭 행 오른쪽 테이블 컬럼은 NULL
RIGHT JOIN 오른쪽 테이블 전체 + 왼쪽 테이블 매칭 행 왼쪽 테이블 컬럼은 NULL
FULL JOIN 양쪽 테이블 전체 (합집합) 매칭 없는 쪽 컬럼은 NULL

3. 그 외 알아두면 좋은 JOIN

 CROSS JOIN (교차 조인, 카디전 곱)

  • 개념: 두 테이블 사이에 아무런 조건(ON 절)을 두지 않고, 양쪽 테이블의 모든 행을 서로 상호 곱하여 가능한 모든 조합을 만드는 연산. 이를 수학 용어로 카디전 곱(Cartesian Product)이라고 한다.
  • 특징: 결과 행의 개수는 A 테이블의 행 개수 × B 테이블의 행 개수가 된다. 데이터가 조금만 많아도 결과가 폭발적으로 늘어나므로 주의.
  • RDB의 SQL 표준 정의(수학적): 이에 따르면, 모든 JOIN의 기본 원리(논리적 모델)는 내부적으로 다음과 같은 단계를 거친다고 설명한다.
    1. 우선 두 테이블의 카디전 곱을 수행해 모든 가능한 조합의 판을 먼저 깔아둔다.
    2. 그 후 ON 조건절에 맞는 행들만 필터링해서 남긴다.
  • 실제 내부 작동(물리적): 실제 데이터베이스 내부의 옵티마이저(Optimizer, 실행 계획 최적화 도구)는 카디전 곱을 만들지 않고, 처음부터 조건에 맞는 데이터만 골라서 연결하는 훨씬 효율적인 알고리즘들을 사용한다.
    • Nested Loop Join (중첩 루프 조인): 한쪽 테이블을 한 행씩 읽으면서, 그에 맞는 데이터만 반대쪽 테이블에서 쏙쏙 찾아 연결한다 (마치 이중 for문 같은 방식).
    • Hash Join (해시 조인): 한쪽 테이블의 조인 키로 해시 테이블(HashMap)을 먼저 만들어두고, 반대쪽 테이블을 읽으면서 매칭되는 데이터만 빛의 속도로 찾아낸다.
SELECT U.name AS 유저이름, O.product_name AS 상품명
FROM Users U 
CROSS JOIN Orders O;

 ② SELF JOIN (자체 조인)

  • 개념: 별도의 문법이 있는 것이 아니라, 하나의 테이블을 자기 자신과 조인하는 것을 말한다.
  • 특징: 하나의 테이블을 두 개처럼 써야 하므로, 별칭(Alias)을 붙여주어야 에러가 나지 않는다.
  • 예시: 사원 테이블에서 '사원'과 '해당 사원의 상사'를 매칭할 때 사용
SELECT 
    e.이름 AS 사원이름, 
    e.직급 AS 사원직급, 
    m.이름 AS 상사이름
FROM 사원 e
JOIN 사원 m ON e.상사사원번호 = m.사원번호;

4. 멀티 조인 (연쇄 조인)

1) 기본 구조 (작성법)

  • 기본적으로 두 개의 테이블을 조인하는 문법 뒤에 JOIN 절을 계속해서 이어 붙이면 된다.
  • SQL은 기본적으로 위에서 아래로, 왼쪽에서 오른쪽으로 순서대로 조인을 처리한다. 
    • 조인이 끝날 때 하나로 합쳐진 커다란 임시 결과 집합 [A + B] 이 만들어 진다.
    • 이것을 다시 왼쪽으로 보고, 조인할 테이블 C를 오른쪽 (새로 붙은 테이블)이 되어 다시 확장된다.
    • ON 절에 해당하는 부분도 이미 이전에 조인 처리되어 합쳐진 결과 테이블이기 때문에 문제 없음 
SELECT 
    A.컬럼, B.컬럼, C.컬럼
FROM 테이블A A
INNER JOIN 테이블B B ON A.공통키 = B.공통키
INNER JOIN 테이블C C ON B.또다른공통키 = C.또다른공통키;

2) ⚠️ 멀티 조인 시 주의해야 할 점 (성능 최적화)

  • 조인 순서와 내부 작동 (물리적 관점)
    • 데이터베이스(Optimizer)는 내부적으로 한 번에 3~4개의 테이블을 동시에 묶지 못한다.
    • 먼저 테이블 A와 B를 조인하여 임시 결과 집합(중간 데이터)을 만들고, 그 결과를 다시 테이블 C와 조인하는 단계적 방식을 거침. (예: Nested Loop Join, Hash Join 등 활용)
    • 따라서 먼저 조인되는 단계에서 데이터의 양을 최대한 줄여주는 것이 전체 쿼리 성능에 결정적인 영향을 미친다.
  • 혼합 조인(INNER + LEFT) 사용 시 주의
    • LEFT JOIN 뒤에 INNER JOIN을 잘못 배치하면, LEFT JOIN으로 살려둔 NULL 값들이 INNER JOIN 조건에 의해 필터링되어 사라질 수 있다.
    • 아예 의도한 것이 아니라면 조인 순서나 조인 종류(Outer/Inner)를 신중하게 결정해야 함
  • 인덱스(Index) 필수 활용
    • 연결고리가 되는 ON 절의 조건 컬럼(U.user_id, O.order_id 등)에는 반드시 인덱스가 걸려 있어야 한다.
    • 인덱스가 없으면 테이블 전체를 하나하나 다 읽어야 해서(Full Table Scan) 테이블 수가 늘어날 때마다 속도가 기하급수적으로 느려.

5.💡성능 최적화(Tuning)를 위한 팁

  • 인덱스(Index) 활용: JOIN 조건(ON 절)에 사용되는 컬럼에는 가급적 인덱스를 생성해 두는 것이 좋다. 인덱스가 없으면 데이터베이스가 전체 테이블을 스캔하느라 속도가 급격히 느려짐.
  • 식별자 명시: 여러 테이블을 조인할 때는 SELECT나 WHERE 절에서 U.user_id, O.order_id와 같이 어떤 테이블의 컬럼인지 명확히(Alias 사용) 적어주는 것이 가독성과 성능 면에서 좋다.