본문 바로가기
Programming/SQL

[CS Study] JOIN 2: 외부 조인과 기타 조인 (김영한의 실전 데이터베이스 기본편)

by Mandy's 2025. 11. 21.

 

OUTER JOIN
  • LEFT OUTER JOIN == LEFT JOIN
  • RIGHT OUTER JOIN == RIGHT JOIN

조인의 특징
  • 자식에서 부모 조인 : 행의 개수가 그대로 유지가 됨.
    • FK → PK
    • 주문은 반드시 한 명의 고객에게 속한다.
  • 부모에서 자식 : 행의 개수가 늘어남
    • PK → FK
    • 부모 테이블의 한 행은 자식 테이블의 여러 행과 매칭될 수 있다.
    • 한 명의 고객이 여러 번 주문할 수 있다.
    -- 부모에서 자식 (1행 -> 2행)
    select
    	o.order_id,
    	o.product_id,
        o.user_id as orders_user_id,
        u.user_id as users_user_id,
        u.name,
        u.email
    from users u
    join orders o on u.user_id = o.user_id
    where o.user_id = 1;
    

실무에서 중요한 이유

  • 조인으로 인해 데이터가 어떻게 변하는지 이해해야 합계, 평균, 개수 같은 집계 함수를 올바르게 사용하고 원하는 분석 결과를 정확하게 도출할 수 있음.
  • 쿼리를 작성하기 전에 항상 어떤 테이블을 기준으로 삼을지, 그리고 조인으로 인해 행 수가 증가하는 상황인지 아닌지, 먼저 생각하는 습관을 들이는 것이 중요하다.

참고: 조인의 유연성

  • 조인의 핵심 원리는 두 테이블의 특정 열의 값이 같은가? - 어떤 열이든 조인 조건으로 쓸 수 있다. (데이터 타입이 같은 경우)
  • 주로 대부분은 pk-fk관계로 사용한다. (데이터의 일관성)

 


셀프 조인
셀프 조인

동일한 테이블을 두 번 참조하여 조인하는 기법

  • 주로 계층 구조나 상하 관계를 표현할 때 사용 (예: 직원-관리자, 카테고리-상위카테고리)
  • 테이블 별칭(alias)을 반드시 사용해야 구분 가능
  • 하나의 테이블을 자기 자신과 조인하는 기법
  • select e.name as employee_name, m.name as manager_name from employees e left join employees m on e.manager_id = m.employee_id; -- 김회장님은 상사가 없다 !

 


크로스 조인
  • 지금까지는 on 이라는 연결고리를 통해 테이블에 이미 존재하는 관계를 찾아내는 작업을 함.
  • 애초에 짝이나 관계가 없는 두 집단을 가지고 가능한 모든 조합을 만들어내려면 어떻게 해야 할까?
  • insert into 를 사용해서 새로운 테이블을 만들 때 유용하게 사용할 수 있음.

실무에서 치명적인 주의사항

  • 크로스조인은 최대한 사용하지 않는 것이 좋음.
  • 결과의 행수가 기하급수적으로 증가할 수 있음.

  • 참고사항
카테시안 곱이란?

💡 JOIN 조건 없이 여러 테이블이 서로 모든 조합으로 곱해져버리는 상황.

ORM에서 자연스럽게 생기는 이유는:

  • 1:N 또는 N:N 관계를 joinedload(fetch join)로 한 번에 가져오면
  • 내부적으로 JOIN을 하게 된다.
  • 이때 JOIN 결과는 원본 테이블의 row 수 × 자식 row 수가 되어
  • row가 폭발하게 된다.

예:

  • Team 100개
  • Member 50명씩

JOIN FETCH 하면 결과 row는 5000개

→ 이것을 흔히 “카테시안 곱처럼 row가 폭발했다”라고 표현함.

정확한 의미의 “진짜 cross join”은 아니지만,

row 폭발 문제 때문에 현업에서는 “카테시안 곱”이라고 불러버리는 경우가 많다.

  • ORM에서 매우 흔하게 발생하는 경우
  • 필요한 것만 가져다가 나눠서 크로스 조인을 사용해야 한다.
  • ORM의 관계 매핑을 사용하는데, 1:N or N:N 관계 매핑이 될 수 있다. (1:1 관계에서는 크게 문제가 되지 않음)
    • 하나의 테이블 기준으로 여러 개의 테이블이 매핑이 되어 있을 때 → 카테시안 곱으로 모든 것을 다 가져온다.

해결방법

  1. selectinload를 사용함.
    • 쿼리를 한 번 더 날리는 것이기 때문에 n+1 ?
  2. 패치 조인; n+1문제를 해결하기 위한 전략
  3. lazy loading을 사용함.
    • 데이터의 크기에 맞게 사용을 해야 함.
  • ORM 은 편하지만 실무에서 사용할 때 주의해야 할 점이 있다!

 

where 절에서 null 이 포함 되지 않는 경우
  • where 절

NULL과 비교하면 결과는 TRUE도 FALSE도 아닌 UNKNOWN이 된다. WHERE는 TRUE만 통과시키고, FALSE와 UNKNOWN은 모두 제외한다.

  • and 표현

AND 자체가 NULL을 포함시키는 게 아니라,

OR 조건 또는 부등호 조건에서 NULL이 의도와 다르게 흘러가는 경우가 많아서 그렇게 느끼는 것

  • NULL과 비교한 결과는 TRUE가 아님 → WHERE에서 제외됨
  • AND / OR 자체가 NULL을 포함하는 것이 아니라,
  • SQL의 UNKNOWN 처리 때문에 논리가 달라져 보일 뿐
  • 정확히 제어하려면 항상 IS NULL 혹은 IS NOT NULL을 명시해야 한다.