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의 기본 원리(논리적 모델)는 내부적으로 다음과 같은 단계를 거친다고 설명한다.
- 우선 두 테이블의 카디전 곱을 수행해 모든 가능한 조합의 판을 먼저 깔아둔다.
- 그 후 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 사용) 적어주는 것이 가독성과 성능 면에서 좋다.
'Language & Tool > sql' 카테고리의 다른 글
| 🗄️CASE문 문법 및 활용법 총정리 (Simple / Searched / SUM() 활용 / ORDER BY절에서의 사용) (0) | 2026.07.06 |
|---|---|
| 🗄️연관관계 매핑 전략과 핵심 개념(다대일, 일대다, 연관관계의 주인) (0) | 2026.07.02 |
| 🗄️서브쿼리 개념 종류 및 JOIN과의 차이점 완벽 정리 (0) | 2026.07.02 |
| 🗄️SQL 쿼리 작성 순서와 실행 순서 (0) | 2026.07.02 |