실무에서 실제로 성능 차이를 만드는 조인(Join) 튜닝 방법을 알아보았다.
DBMS 종류와 상관없이 공통적으로 적용되는 원칙 위주로 알아봤다.
대부분의 DB 옵티마이저는 조인 순서를 자동으로 최적화하지만, 통계 정보가 부정확하거나 힌트를 주면 순서를 바꿀 수 있다.
-- A 테이블은 조건으로 100건만 나오고,
-- B 테이블은 전체 100만건에서 조건 없다고 가정
SELECT ...
FROM A
JOIN B ON ...
WHERE A.status = 'ACTIVE';
A를 먼저 읽는 것이 유리하다.
조인 시 가장 중요한 원칙은 ON 조건의 양쪽 컬럼 모두가 인덱스 후보인지 확인하는 것이다.
JOIN orders o ON o.user_id = u.id
WHERE u.status = 'ACTIVE'
여기서는 users(status, id) 또는 users(status) + orders(user_id) 형태 인덱스가 유리.
DB는 자신이 판단하여 join 방식을 선택한다. 하지만 패턴에 따라 성능 차이가 크게 난다.
옵티마이저가 오판하는 경우 힌트로 선택할 수 있음.
타입이 다르면 인덱스를 못 쓰고 Full Scan + 함수 연산이 발생함.
INT vs VARCHARCHAR(10) vs VARCHAR(10)timestamp vs dateSELECT *
FROM orders o
JOIN users u ON o.user_id = CAST(u.id AS VARCHAR)
→ Index 사용 못함 + Hash join 강제
중복 데이터 조인은 매우 큰 성능 손실을 준다.
SELECT *
FROM users u
WHERE EXISTS(
SELECT 1 FROM orders o WHERE o.user_id = u.id
)
조인을 하기 전에 필터링하는 게 조인 후 필터링보다 5~100배 이상 빠르다.
SELECT ...
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.created_at >= '2024-01-01';
SELECT ...
FROM (
SELECT *
FROM orders
WHERE created_at >= '2024-01-01'
) o
JOIN users u ON o.user_id = u.id;
대량 테이블 orders를 먼저 줄여놓으면 조인 비용 급감.
LEFT JOIN / RIGHT JOIN은 조건 푸시다운이 안 되는 경우가 있음.
SELECT *
FROM a
LEFT JOIN b ON a.id = b.a_id
WHERE b.status = 'ACTIVE';
이는 사실상 INNER JOIN이지만
DB는 먼저 OUTER JOIN을 한 뒤 WHERE에서 필터링 → 성능 저하.
SELECT *
FROM a
JOIN b ON a.id = b.a_id AND b.status = 'ACTIVE';
→ 조인 조건에서 필터를 넣어야 성능 좋음
정말 많은 튜닝 사례에서 발견되는 문제:
SELECT ...
FROM users u
JOIN orders o ON ...
JOIN orders o2 ON ...
실제로 o2가 필요 없는 경우가 많다.
대용량 ETL·통계 쿼리에서 자주 사용하는 방법.
→ 특히 페타바이트 데이터 웨어하우스에서 거의 필수
실제 조인 튜닝의 핵심은 실행 계획이다.
실행 계획 없이 조인 튜닝은 거의 불가능하다.