개념
- join 순서와 인덱스
인덱스 레인지 스캔은 인덱스 탐색과 인덱스 스캔으로 구성되어있다. 일반적으로 인덱스에서 가져와는 건수가 소량이기 때문에 인덱스 스캔 작업은 부하가 작지만 특정 인덱스 키를 찾는 인덱스 탐색 작업은 상대적으로 부하가 높다. 조인 작업에서 드라이빙 테이블을 읽을 때는 탐색을 단 한 번만 수행하고, 이후부터는 스캔만 실행하면 된다. 하지만 드리븐 테이블에서는 인덱스 탐색과 스캔 작업을 드라이빙 테이블에서 읽은 레코드 건수만큼 반복한다. 드라이빙 테이블과 드리븐 테이블이 1:1로 조인되더라도 드리븐 테이블을 읽는 것이 훨씬 더 큰 부하를 차지한다. 따라서 옵티마이저는 항상 드라이빙 테이블이 아니라 드리븐 테이블을 최적으로 읽을 수 있게 실행 계획을 수립한다.
inner join에서는 인덱스를 타는 지에 따라 드라이빙 드리븐 테이블을 옵티마이저가 계산해서 최적화한다.
- 두 컬럼 모두 인덱스가 있는 경우: 옵티마이저가 적절히 드라이빙 테이블을 선택한다.
- 드라이빙 테이블에만 인덱스가 있는 경우 or 드리븐 테이블에만 인덱스가 있는 경우: 인덱스를 사용할 수 있는 쪽을 드리븐 테이블로 이용한다.
- 둘 다 없는 경우: 건수가 적은 테이블을 드라이빙 테이블로 선택한다.
- OUTER JOIN 의 성능과 주의사항
inner join은 조인 대상 테이블에 모두 존재하는 레코드만 결과 집합으로 반환하기 때문에 종종 outer join으로만 조인을 실행하는 쿼리들도 있다 하지만 outer join을 사용하면 mysql 옵티마이저는 절대 아우터로 조인되는 테이블을 드라이빙 테이블로 선택하지 못하기 때문에 드라이빙 테이블을 풀스캔한다. 그 결과 옵티마이저가 조인 순서를 바꿔 최적화 할 수 있는 기회를 박탈하게 된다.
항상 드라이빙 테이블부터 풀스캔 하면서 드리븐 테이블을 사용한다. 단 하나 row만 조회하는 경우라도 드라이빙 테이블을 풀스캔하는 것을 알 수 있다. 즉 outer join을 사용하면 옵티마이저가 조인 순서를 변경하면서 수행할 수 있는 최적화의 기회를 빼앗아 버리게 된다. 따라서 꼭 필요한 경우가 아니라면 INNER JOIN을 사용하는 것이 구현도 정확해지고 쿼리 성능도 향상시킨다.
참고로 outer join 의 테이블에 where 조건을 붙이면 innerjoin으로 변환해서 실행되기 때문에, 의도한 동작을 하지 않을 수 있다. 따라서 left join에 조건문을 걸 때에는 on 절에 조건문을 사용해야한다.
조건절을 JOIN의 ON절에 사용할지, WHERE 절에 사용할 지?
=> 사용하고자 하는 용도에 따라 다르다. INNER JOIN에서는 성능상의 차이가 없고 OUTER JOIN에서는 다른 의미로 해석될 수 있기 때문에 위의 내용을 고려해서 작성해야한다.
'백엔드 개발' 카테고리의 다른 글
#037. 리팩터링: one-size fits all API 만들기 (0) | 2023.06.01 |
---|---|
#036. 쿼리개선: insert 성능과 테이블 구조 (Index 정리하기) (0) | 2023.05.13 |
#034. 쿼리개선: "연산"을 해서 index를 사용하지 못한 쿼리 개선 (0) | 2023.04.25 |
#033. 리팩터링: Transaction DB 와 Query DB 분리하기 (Mikro ORM) (0) | 2023.04.21 |
#032. GCP 서비스로 개발 환경 배포하기(spring profile + cloudrun + cloudflare) (0) | 2023.04.12 |