MySQL 성능 문제를 보다 보면 조인이 느려서 전체 쿼리가 무거워지는 경우를 자주 만납니다. 특히 개별 테이블 조회는 빠른데 여러 테이블을 붙이는 순간 갑자기 느려지는 패턴은 실무에서 꽤 흔합니다.
이 글에서는 아래 내용을 정리합니다.
- join 쿼리가 왜 느려지는지
- 어떤 기준으로 원인을 좁혀야 하는지
- 인덱스와 조인 순서를 어떻게 봐야 하는지
- EXPLAIN에서 무엇을 중점적으로 보면 좋은지
핵심은 join 성능 문제는 테이블 수가 많아서 생기는 것이 아니라, 조인 대상 row 수와 접근 경로가 비효율적일 때 커진다는 점입니다.
join이 왜 느려질까
대표적인 원인은 아래와 같습니다.
- 조인 키에 인덱스가 없음
- 너무 많은 row를 먼저 읽음
- 필터링이 늦게 적용됨
- 큰 테이블끼리 넓게 붙음
- 정렬이나 그룹화 비용이 추가됨
즉, join 문제는 단순히 JOIN 문법의 문제가 아니라, 어느 시점에 얼마만큼의 row를 붙이느냐의 문제입니다.
무엇부터 확인할까
실무에서는 아래 순서가 좋습니다.
- 어떤 테이블이 가장 많은 row를 읽는지 보기
- 조인 키 인덱스가 있는지 확인
- 필터를 먼저 줄일 수 있는지 보기
- EXPLAIN에서 join 순서와 rows 보기
특히 “어떤 테이블을 먼저 좁히는가”가 성능 차이를 크게 만들 수 있습니다.
조인 키 인덱스는 왜 중요한가
조인에서 한쪽 row를 읽을 때 반대편에서 매번 대량 스캔이 일어나면 비용이 급격히 커집니다. 그래서 조인 키 인덱스는 거의 기본 점검 항목입니다.
예를 들어:
orders.user_id = users.id
같은 관계에서 user_id 쪽 인덱스가 부실하면 읽는 양이 크게 늘 수 있습니다.
필터를 먼저 줄이는 것이 왜 중요할까
조인 전에 후보 row 수를 최대한 줄이면 이후 조인 비용이 같이 줄어듭니다.
즉:
- 작은 집합을 먼저 만들고
- 그 뒤 필요한 테이블을 붙이는 방식이
큰 집합을 통째로 붙이는 것보다 훨씬 유리할 때가 많습니다.
EXPLAIN에서는 무엇을 볼까
join 분석에서도 기본은 같습니다.
typekeyrowsExtra
특히 rows가 큰 테이블이 어디인지, key가 안 잡히는 지점이 어디인지 먼저 보는 것이 좋습니다.
자주 하는 오해
1. 테이블이 두세 개면 join은 무조건 괜찮다
적은 수의 테이블이라도 row 수와 인덱스가 나쁘면 충분히 느릴 수 있습니다.
2. JOIN을 없애면 무조건 빨라진다
오히려 쿼리 수를 늘려 N+1 문제로 이어질 수도 있습니다.
3. 조인 성능은 DB가 알아서 최적화한다
MySQL이 최적화를 하더라도 인덱스와 쿼리 구조가 나쁘면 한계가 있습니다.
FAQ
Q. join이 느릴 때 가장 먼저 볼 것은 무엇인가
조인 키 인덱스와 가장 많은 row를 읽는 테이블입니다.
Q. 작은 테이블부터 붙이면 항상 좋은가
항상 그런 것은 아니지만, 후보 row를 빨리 줄이는 방향이 대체로 유리합니다.
Q. join과 N+1 중 어느 쪽이 더 나은가
상황에 따라 다르지만, 보통은 쿼리 수와 조인 복잡도 사이의 균형을 봐야 합니다.
Read Next
- 실행 계획 읽기는 MySQL EXPLAIN 가이드와 자연스럽게 이어집니다.
- 쿼리 수 폭증 문제는 MySQL N+1 query 가이드도 함께 보면 좋습니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
- Docker container가 계속 재시작될 때: 먼저 확인할 것들 exit code, command failure, environment mistake, health check 관점에서 Docker restart loop를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.