서론
프로젝트 성능 향상을 위해 JOIN 관련해서 공부하던 중 의문점이 생겼습니다.
문제 상황은 아래와 같습니다.
1. 10^4건의 데이터를 가진 테이블 A와 B가 있다.
2. 두 테이블을 인덱스가 없는 칼럼을 기준으로 JOIN 할 경우 10^4 * 10^4 의 시간복잡도를 가지기 때문에 최소 1초는 걸릴 것이라 생각했다.
3. 실행 결과 15ms가 나왔다.
쿼리문은 아래와 같습니다.
SELECT p.content
FROM post AS p
JOIN study AS s ON p.posted_user_id = s.master_user_id;
쿼리 실행계획을 통해 왜 예상과 다른 결과가 나왔는지 확인해보겠습니다.
본론
EXPLAIN ANALYZE 키워드로 확인한 결과 Inner hash join을 사용해 join하고 있었습니다.
해시 조인은 인덱스가 없는 칼럼으로 조회할 때 성능을 높일 수 있기 때문에 옵티마이저가 임의로 해시 조인을 하는 방식을 택한 것으로 보입니다.
확인을 위해 인덱스가 있는 칼럼인 s.study_id를 기준으로 JOIN 해보겠습니다.
EXPLAIN ANALYZE SELECT p.content
FROM post AS p
JOIN study AS s ON p.posted_user_id = s.study_id;
인덱스가 있는 칼럼을 기준으로 JOIN하니 Nested loop join을 하고있습니다.
그렇다면 왜 해시조인을 해서 성능이 좋아진걸까요??
이는 해시 조인의 동작 방식 때문입니다.
해시 조인 동작 방식
SELECT p.content
FROM post AS p
JOIN study AS s ON p.posted_user_id = s.master_user_id;
위 쿼리문에서 해시 조인을 하게될 경우 순서를 살펴보겠습니다.
1. post 테이블을 build input으로 삼아서 해시 영역에 저장한다.
2. 해시 영역으로 올라가면서 join 컬럼인 posted_user_id를 기준으로 hash function이 적용된다.
3. study 테이블의 master_user_id를 hash function을 적용해 해시 영역에 해당 값이 있는지 확인한다.
이 같은 방식으로 진행되기 때문에 10^4개의 데이터를 JOIN 할 때 O(n^2)이 아닌 O(n)의 시간복잡도만 가지게 되어 성능이 빨라지는 것입니다.
NL 조인 했을때의 성능
해시 조인 했을 때 성능이 빨라지는 것은 알겠는데 과연 NL 조인을 하면 얼마나 느려질지 궁금했습니다.
MySQL 공식문서를 보면 8.0.18 버전 이후로 해시 조인을 사용할 수 있으면 기본적으로 사용한다고 나와있습니다.
강제로 해시 조인을 사용하지 않기 위해 set optimizer_switch='block_nested_loop=off'; 쿼리문을 실행한 뒤 아래 쿼리문의 성능을 다시 측정해보겠습니다.
EXPLAIN ANALYZE SELECT p.content
FROM post AS p
JOIN study AS s ON p.posted_user_id = s.master_user_id;
강제로 NL 조인을 실행시킨 결과 28.171s로 측정되었습니다.
결론
해시 영역에 들어가는 테이블의 크기가 너무 크게되면 디스크 영역을 사용하기 때문에 성능이 더 나빠지는 결과를 초래할 수 있습니다.
옵티마이저의 실행계획을 따라가되 성능이 나쁘게 측정된다면 쿼리 튜닝을 고려해 보는 것이 좋겠습니다.
'개발 > Database' 카테고리의 다른 글
InnoDB FullText-Index를 이용한 검색 성능 향상 (1) | 2024.04.25 |
---|---|
MySQL InnoDB B-Tree Index 탐색 과정 분석 (0) | 2024.04.11 |
[StudyHub] 성능 관점에서 확인해본 조회 쿼리문 (0) | 2024.02.11 |
[StudyHub] 다중 칼럼 인덱스를 이용한 조회 성능 개선 (0) | 2024.01.12 |
[StudyHub] FK 매핑으로 인한 외래키 참조 무결성 문제 해결 (2) | 2024.01.01 |