시작하며

JOIN의 종류로는 INNER JOIN, OUTER JOIN, CROSS JOIN 세 가지가 있습니다. 이중 INNER JOIN과 OUTER JOIN이 많이 사용되고, CROSS JOIN은 일반적인 운영 환경 보다는 MART 시스템과 같은 통계 시스템에서 주로 사용합니다. 이번 글에서는 INNER JOIN을 알아보겠습니다.


특정 성씨 출력

INNER JOIN을 수학에 비유하면 교집합과 같습니다. 우선 형식부터 보시죠.

SELECT
	T101.MBR_ID
	,T101.MBR_NM
	,T101.AREA_ID
	,T102.AREA_NM
FROM test.TB_MBR_BAS T101
	INNER JOIN test.TB_AREA_BAS T102
		ON T102.AREA_ID = T101.AREA_ID
;



01


02


위의 명단에서 신씨인 사람만 출력해보겠습니다.

SELECT
	T101.MBR_ID
	,T101.MBR_NM
	,T101.AREA_ID
	,T102.AREA_NM
FROM test.TB_MBR_BAS T101
	INNER JOIN test.TB_AREA_BAS T102
		ON T102.AREA_ID = T101.AREA_ID
WHERE T101.MBR_NM LIKE '신%'
;



03


04


T101.MBR_NM LIKE '신%' 조건이 추가되면서 PLAN의 T101 type이 ALL 에서 range 로 바뀌었습니다. key는 IX_MBR_BAS_02 INDEX로 바뀐 것을 확인할 수 있고, 이에 따라 이름 순으로 정렬 및 출력되었습니다.


특정 지역 출력

이번에는 지역이 서울특별시인 사람만 출력해보겠습니다.

SELECT
	T101.MBR_ID
	,T101.MBR_NM
	,T101.AREA_ID
	,T102.AREA_NM
FROM test.TB_MBR_BAS T101
	INNER JOIN test.TB_AREA_BAS T102
		ON T102.AREA_ID = T101.AREA_ID
		AND T102.AREA_NM = '서울특별시'
;



05


06


PLAN을 보면 T101의 전체 자료를 읽으면서 T102와 JOIN 후 AREA_NM = '서울특별시' 인 것을 출력합니다. 이렇게 하면 T101의 전체 자료 중 서울특별시가 아닌 것을 읽은 뒤, 버리게 되는 낭비가 발생하는데요. 그렇다면 test.TB_AREA_BAS 를 먼저 읽은 뒤, 서울특별시만 읽고 test.TB_MBR_BAS 를 JOIN하는 건 어떨까요? 분명 낭비를 줄일 수 있을 겁니다. 한 번 위치를 바꿔보겠습니다.

SELECT
	T102.MBR_ID
	,T102.MBR_NM
	,T101.AREA_ID
	,T101.AREA_NM
FROM test.TB_AREA_BAS T101
	INNER JOIN test.TB_MBR_BAS T102
		ON T102.AREA_ID = T101.AREA_ID
WHERE T101.AREA_NM = '서울특별시'
;



07


PLAN을 보세요. test.TB_AREA_BAS T101 가 먼저 오도록 하고 싶었지만, T102와 T101이 PLAN상 위치만 바뀌었을 뿐 기존 Query와는 다르지 않은 것을 알 수 있습니다. PLAN 순서가 바뀐 이유는 MySQL 내부에서 test.TB_MBR_BAS 이 먼저 오는 게 최적이라고 판단했기 때문입니다. 이렇게 내부적으로 바뀐 PLAN을 사용자 의도대로 유도하려면 힌트를 사용합니다. 예시에서는 STRAIGHT_JOIN 힌트를 사용하겠습니다.

SELECT STRAIGHT_JOIN
	T102.MBR_ID
	,T102.MBR_NM
	,T101.AREA_ID
	,T101.AREA_NM
FROM test.TB_AREA_BAS T101
	INNER JOIN test.TB_MBR_BAS T102
		ON T102.AREA_ID = T101.AREA_ID
WHERE T101.AREA_NM = '서울특별시'
;



08


STRAIGHT_JOIN 힌트를 사용해 테이블 순서는 의도대로 변경되었지만 type이 모두 ALL 로 되어 있어서 비효율적입니다. 먼저 test.TB_AREA_BAS인 T101에서 type이 ALL 로 나타나는 것은 AREA_NM 컬럼에 INDEX 가 없기 때문입니다. test.TB_AREA_BAS 에 INDEX를 추가해보겠습니다.

CREATE INDEX IX_AREA_BAS_01 ON test.TB_AREA_BAS (AREA_NM);



09


INDEX를 추가한 뒤의 PLAN을 보면 T101에서 INDEX 를 타는 걸 확인할 수 있습니다. 다음으로 test.TB_MBR_BAS에 INDEX를 추가해보겠습니다.

CREATE INDEX IX_MBR_BAS_03 ON test.TB_MBR_BAS (AREA_ID);



10


PLAN에 T102도 INDEX를 타는 것이 확인됩니다. 수행해봅시다.

11


위의 수행 결과에서 STRAIGHT_JOIN 힌트를 제거해볼까요?

SELECT
	T102.MBR_ID
	,T102.MBR_NM
	,T101.AREA_ID
	,T101.AREA_NM
FROM test.TB_AREA_BAS T101
	INNER JOIN test.TB_MBR_BAS T102
		ON T102.AREA_ID = T101.AREA_ID
WHERE T101.AREA_NM = '서울특별시'
;



12


PLAN이 INDEX를 추가했어도 STRAIGHT_JOIN 힌트와 상관 없이 동일합니다. INDEX가 제대로 구성되어 있다면 STRAIGHT_JOIN 힌트를 굳이 사용하지 않아도 된다는 것을 알 수 있습니다. 다만 Query가 복잡해지면 MySQL이 판단해 PLAN을 만들더라도 최적이 아닌 때가 생깁니다. 그럴 땐 사용자가 의도하는 대로 힌트를 사용하면 됩니다.

특정 성씨와 지역 출력

이번에는 신씨 중에서 서울특별시에 사는 사람을 출력해보겠습니다.

SELECT
	T102.MBR_ID
	,T102.MBR_NM
	,T101.AREA_ID
	,T101.AREA_NM
FROM test.TB_AREA_BAS T101
	INNER JOIN test.TB_MBR_BAS T102
		ON T102.AREA_ID = T101.AREA_ID
		AND T102.MBR_NM LIKE '신%'
WHERE T101.AREA_NM = '서울특별시'
;



13


04


위와 같은 Query로 TABLE에 대해 각각 조건을 부여해 출력할 수 있습니다.


마치며

지금까지 INNER JOIN을 알아봤습니다. Query를 작성할 때에는 항상 PLAN을 확인해 의도한 대로 나타나는지 확인해야 합니다. 만약 의도한 것과 다르다면 INDEX를 점검하고, 힌트를 사용해 조정하면 됩니다. 다음 글에서는 OUTER JOIN을 알아보겠습니다.


한석종 부장 | R&D 데이터팀
hansj@brandi.co.kr
브랜디, 오직 예쁜 옷만