2026 01 05
2026-01-05¶
Semi-Join & Exists¶
- 개념
- 두 테이블을 조인할 때, 데이터를 실제로 합치는 것이 아닌, "존재 여부만 확인" 하는 기법
- 데이터를 가져올 필요 없이 있는지만 궁금할 때에는
EXISTS가 훨씬 빠르다. MySQL은 Semi-Join으로 이를 해결 - 중복 제거 자동 적용
- Semi-Join (반쪽 조인)
- 일반적인 Inner Join은 교집합 데이터를 모두 만듦
- Semi-Join은 "Outer 테이블의 행이 Inner 테이블에 존재하는가"만 판단
- 판단 후 즉히 Outer 테이블의 행으로 넘어감
- 왼쪽 테이블에서 오른쪽 테이블과 매칭되는 행만 반환 + 오른쪽 테이블의 데이터는 가져오지 않음
- 문제
JOIN+GROUP BY는, 데이터를 모두 펼쳐놓고 조인하고, 다시 묶어서 그룹핑 갯수를 세기에 메모리를 많이 먹고 느림
- 개선
- MySQL은
IN혹은EXISTS서브 쿼리를 만났을 때, 내부적으로 Semi-Join 최적화 진행 - FirstMatch, Materialization, Duplicate Weedout
- MySQL은
- 예시
Users: 10,000명Orders: 1,000,000건- 한 번이라도 주문한 적 있는 회원 목록 추출
-
[Bad Case]
- 회원 A가 주문했는지는 첫번째만 봐도 아는데, 굳이 100번 가량 조인 - [Good Case]
- Outer Loop:
Users테이블에서 회원 A가져옴 - Inner Loop:
Orders테이블의 인덱스 타고 회원 A의 주문을 찾음 - Short-circuit: 주문 내역 하나라도 발견시 (First Match), 회원 A의 주문 찾지 않고 멈춤
-
- MySQL 옵티마이저
- MySQL 8.0 이후 부터는
IN,EXIST쿼리 작성시, 옵티마이저가 자동으로 Semi-Join 최적화 수행함
- MySQL 8.0 이후 부터는
스칼라 서브쿼리¶
- 서브쿼리의 결과가 단일 값으로 나오는 쿼리. WHERE 절 안에서 특정 갯수가 값을 비교할 때 사용하는, 결과가 딱 하나만 나오는 미니 쿼리
- 각 유저 행마다 실행되지만, 인덱스를 타면 매우 빠름
- SELECT 절이나, WHERE 절에서 변수처럼 비교 가능
Correlated Subquery & attached_subqueries¶
- 메인 쿼리의 컬럼을 참조하는 서브쿼리
- 메인 쿼리의 각 행마다 붙어서 실행되는 조건을 의미
- 상관 서브쿼리는 느리다는 오해가 있지만, 최신 DB Optimizer는 인덱스 Lookup을 통해 효율적으로 처리하도록 진화
eq_ref (Primary Key Lookup)¶
- MySQL 실행계획 EXPLAIN type 중 하나 (eq_ref)
- Join 시, Primary Key/Unique Key를 사용해 단 1건의 데이터만 조회한다는 뜻
- 예시)
- 현재 enrollment 테이블의 PK는 (user_id, company_id)
- 서브쿼리 돌릴 필요 없이, PK로 콕 찍어서 확인 (
eq_ref)
쿼리 최적화 여정¶
- Short-Circuit Evaluation
- 앞의 조건이 False면 뒤의 조건은 실행하지 않도록
EXISTS (조건A) AND EXISTS (조건B)
- 인덱스 explain
typesystem/const: 테이블에 데이터 1건이거나 상수로 PK 조회하는 경우eq_ref: 테이블 조인할 때 딱 PK/Unique Key로 1건만 읽음ref: 인덱스를 타지만, 결과 여러개일 수 있음range: 범위 검색index: 인덱스 전체 스캔ALL: 테이블 전체 스캔