전문가칼럼

DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.

그림으로 배우는 ‘오라클 조인의 방식’ 이야기

전문가칼럼
DBMS별 분류
Oracle
작성자
dataonair
작성일
2015-01-13 00:00
조회
22353




◎ 연재기사 ◎


물탱크 구조로 알아본 오라클의 블록 옵션 ‘PCTFREE와 PCTUSED’


이산가족 찾기 생방송을 통해 배우는 DB 원리


개발자에게 맞는 DB 공부방법 찾기: 물리적 분류와 논리적 분류 그리고 인덱스


데이터베이스 인덱스의 오해와 진실


쉬운 것이 올바른 것이다. ‘인덱스 끝장리뷰’ (상)


쉬운 것이 올바른 것이다. ‘인덱스 끝장리뷰’ (하)


누구도 알려주지 않았던 ‘오라클 인덱스 생성도’의 비밀


누구도 알려주지 않았던 ‘오라클 쿼리 작성의 비법’


퀴리 최적화 및 튜닝을 위한 오라클 공정쿼리 작성법


만능 쿼리와 한 방 쿼리


오라클 옵티마이저 ‘CBO와 RBO’ 이해하기


재미있는 DB 이야기 ‘60갑자와 쿼리’


그림으로 배우는 ‘오라클 조인의 방식’ 이야기


반드시 알아야 하는 오라클 힌트절 7가지


오라클 플랜을 보는 법


개발자들의 영원한 숙제 ‘NULL 이야기’


알면 유용한 오라클 기능 ‘GATHER_PLAN_STATISTICS’


알면 유용한 오라클 기능들


오라클 DICTIONARY를 활용한 DB툴 프로그램 ‘FreeSQL’


이제는 말할 수 있다: 주식 자동매매 프로그램(상)


이제는 말할 수 있다: 주식 자동매매 프로그램(하)


개발자들이 자주 접하는 오라클 에러 메세지


재미있는 DB 이야기 ‘사라진 날짜를 찾아라’


오라클 랜덤 함수와 사용자 정의 함수


그림으로 배우는 ‘공정쿼리와 인덱스 생성도’


이병국의 개발자를 위한 DB 이야기: 디폴트 세팅의 함정과 오라클 파라미터


재미있는 DB 이야기 ‘놀라운 마방진의 세계’


오라클 운반 최소 단위 BLOCK


이병국의 개발자를 위한 DB 이야기: 이세돌과 알파고의 세기의 대결


이병국의 개발자를 위한 DB 이야기(30회) : DB 엔지니어의 가볍게 읽는 세상 이야기


이병국의 개발자를 위한 DB 이야기: 튜닝(31회) : 개발자를 위한 DB 튜닝 실전(1편)


이병국의 개발자를 위한 DB 이야기: 튜닝(32회) : 개발자를 위한 튜닝 실전(2편)


이병국의 개발자를 위한 DB 이야기: 튜닝(33회) : 개발자를 위한 튜닝 실전(3편)


이병국의 개발자를 위한 DB 이야기: 튜닝(34회) : 개발자를 위한 DB 튜닝 실전(4편)


이병국의 개발자를 위한 DB 이야기: 튜닝(35회) : 개발자를 위한 튜닝 실전(5편)


이병국의 개발자를 위한 DB 이야기: 페이징 처리에 대한 이해 (36회)


보기 좋은 떡이 먹기도 좋다 - 좋은 쿼리 좋은 성능


테이블의 수직분할과 수평분할에 대한 이해


DB 성능 제고를 위한 채번의 이해와 방식별 장단점 비교


이병국의 개발자를 위한 DB 이야기: 마지막회 : ‘개발자를 위한 DB 이야기’ 연재를 마치며



이병국의 개발자를 위한 DB 이야기: 튜닝 (13회)

그림으로 배우는 ‘오라클 조인의 방식’ 이야기



이병국 andongcn@dreamwiz.com
프리랜서 DB 엔지니어로서 동아제약 전산실에서 SW 개발 업무를 시작으로 프리랜서 개발자로 독립해 활동하던 중 우연한 기회에 DB와 인연을 맺게 됐다. 현재 삼성생명 전산 운영팀에서 쿼리 성능을 개선하는 DB 튜닝과 IOA 업무를 맡고 있다.
개발자 출신의 DB 엔지니어로 활동하면서 개발자에게 DB 관련 지식이 꼭 필요함을 절감했다. ‘정보의 불균형이 시장 왜곡을 가져온다’는 ‘레몬시장이론’은 중고차 거래에서 흔히 나타나기 쉽다. 좋은 차와 나쁜 차를 아는 중개인과 모르는 구매자 사이에는 정보의 비대칭 때문에 구매자가 손해를 볼 수 있다. 구매자도 차에 대해 기본적인 지식을 알고 있어야, 정보의 균형이 맞으므로 서로 손해를 보지 않고 합리적인 가격에 차를 거래할 수 있다. 마찬가지로 개발자들도 DB에 대해 기본적인 지식을 습득해 정보의 균형을 맞추면, DB 엔지니어와 협업이 더 쉬워지고 한 단계 더 발전한 자신의 모습을 발견할 것이다.



성공과 실패의 경험을 나누자, 용기와 희망을 나누자
개발업무를 시작으로 IT계에 입문했던 필자가 10년 가까이 DB 엔지니어로서 활동하면서
얻은 경험과 지식을 나누고자 한다. DB를 자주 접하는 SW 개발자뿐 아니라, DB 전문가를 꿈꾸는 대학생에서
DB 분야에 입문한 지 1~2년 된 기 입문자가 쉽게 이해할 수 있도록 비유를 통해 쉽게 접근해볼 계획이다.
물론 전문가들이라도 다시 한번 개념을 정립하는 의미에서 필요한 내용이 될 수 있다.
전체적으로 DB의 기본 원리와 개념을 이해하고 테이블, 인덱스, 쿼리, 튜닝, 플랜 등 개발자들이
알아야 하는 DB 전분야에 대해 쉽게 이해하도록 설명하겠다. DB 기술서적이나 번역서보다는
조금 더 부드럽게 접근할 계획이다. 그렇다고 흔히 서점에서 만날 수 있는 개발자 위주의 SQL 소개서도 아니다.
이 연재는 시리즈로 나갈 것이다. 연재를 끝까지 읽는 독자라면, 준전문가 수준의 DB 원리를 아는 것을 목표로 한다.

이번 연재에서는 오라클의 조인 방식에 대해 설명하고자 한다. 가능한 한 쉽고 편안하게 읽을 수 있도록 그림을 많이 활용하였다.


조인이란 무엇인가

흔히 조인이라 하면 Inner Join 혹은 Outer Join을 생각하는 경우가 많다. 이번 연재 내용은 그러한 조인이 아니라 테이블 간에 어떤 방식으로 접근하는가에 대한 조인이다. 다시 말해서 오라클에서 조인 방식이란, 테이블 간의 데이터 접근 방법을 의미한다.


관계형 데이터베이스에서 쿼리는 Join 없이 단독으로 사용하는 경우가 거의 없다. 대부분의 쿼리는 여러 테이블 간에 관계를 맺는 경우이다. 이러한 테이블 간 관계에 있어서 어떠한 방법으로 접근하는가에 대한 내용이 바로 조인 방식에 대한 내용이다. 오라클에서 조인은 아주 중요한 의미를 가진다. 왜냐하면 어떠한 조인 방식을 선택하느냐에 따라서 쿼리의 비용과 성능이 달라지기 때문이다.


조인 방식은 아래와 같이 크게 3가지 경우로 나뉜다.


1. Nested Loop Join: 순차적 루프에 의한 접근 방식

2. Sort Merge Join: 정렬을 통한 접근 방식

3. Hash Join: 해시 함수를 이용한 접근 방식


도시 사이를 이동할 때, 선택할 수 있는 교통 수단은 택시, 버스, 기차, 자전거, 도보 등이 있다. 어떤 교통 수단이 좋고, 어떤 교통 수단이 나쁘다고 논하는 것은 의미가 없다. 단지 그때그때 상황에 맞게 적절한 수단을 선택하면 되기 때문이다. 소수의 인원이 빨리 가기를 원한다면 택시를 타면 될 것이고, 많은 사람이 이동해야 한다면 버스를 선택하면 된다. 가까운 거리에 있는 도시라면 자전거를 이용할 수도 있고, 더 가까운 거리라면 걸어가는 것도 좋은 방법이다. 도보로 갈 수 있는 거리를 버스 타고 이동한다면 아까운 비용만 지불한 꼴이 될 것이다. 택시를 타고 빨리 가야 할 거리를 걸어서 간다면 비용은 아꼈을지 몰라도 그만큼 시간을 쓴 것이다.


마찬가지로 오라클에서도 조인 방식에 따른 호불호는 없다. 단지 상황에 따른 선택만 있을 뿐이다. Nested Loop Join은 택시와 비슷하다. 소량의 데이터 처리에 적합한 조인 방식이다. Hash Join 방식은 버스와 비슷하다. 대량의 데이터 처리에 효율적인 조인 방식이다. Sort Merge Join 방식은 요즘 거의 사용하지 않으므로 논외로 하겠다. 3가지 조인 방식에 대해 좀 더 구체적으로 살펴 보자.


오라클 조인 방식 - Nested Loop Join

Nested Loop Join(NL 조인)은 여러분이 가장 흔하게 접할 수 있는 오라클 조인 방식일 것이다. OLTP(Online Transaction Processing) 쿼리에서 가장 일반적이고 흔한 조인 방식이다. 소량의 데이터를 처리하거나 부분범위 처리에 적합하다. NL 조인의 방식은 아래의 For 문으로 이해하면 쉽다.


column_img_1610.png

개발자라면 For ~ Loop 문의 수행 방법을 알 것이다. NL 조인은 이러한 For ~ Loop 문의 수행 방법과 동일한 것으로, 테이블 간 조인을 순차적으로 수행한다. 테이블 간 접근 순서가 매우 중요하고, 선행 테이블의 처리 범위가 작아야 하고, 조인절의 목적지 컬럼에 반드시 인덱스가 존재해야 한다.


Nested Loop Join 처리 순서는 다음과 같다.


1. 고객 테이블에서 이름이 ‘홍길동’인 고객을 구한다. (선행 테이블 결정)

2. ‘홍길동’ 고객의 수만큼 순차적으로 주문 테이블을 고객번호 컬럼으로 접근한다. (순차적 접근)

3. 주문 테이블에서 주문일자가 ‘20141201’인 정보만 필터한다.


오라클 조인 방식 - Sort Merge Join

오라클 조인 방식 Sort Merge Join은 성능이 더 좋은 Hash Join으로 대체할 수 있기 때문에 여러분이 접할 가능성은 거의 없다. 이 조인 방식은 조인절에 인덱스가 없을 때 자주 발생한다. Sort가 발생하므로 대상 건수가 많을수록 Sort 부하가 커진다. 따라서 성능이 저하될 수 있다. 초등학교 다닐 때 선생님이 짝꿍을 정해 주는 방법과 같은 방법이라 할 수 있다.


column_img_1611.png

column_img_1612.png

Sort Merge Join 처리 순서는 다음과 같다.


1. 고객 테이블에서 이름이 ‘홍길동’인 고객을 구한 후 고객번호 순으로 정렬한다. (SORT)

2. 주문 테이블에서 주문일자가 ‘20141201’인 주문을 구한 후 고객번호 순으로 정렬한다. (SORT)

3. 정렬된 고객 정보와 정렬된 주문 정보를 고객번호로 조인한다. (MERGE)



오라클 조인 방식 - Hash Join

오라클 조인 방식 Hash Join은 대량의 데이터 처리에 유리하다. NL 조인의 처리 범위가 부담스럽거나, Sort Merge Join의 Sort가 부담스러울 때 사용하면 좋다.

메모리에 해시 테이블을 생성하고, 해시 함수를 이용해 연산 조인을 함에 따른 CPU 사용이 증가할 수 있으므로 조회 빈도가 높은 온라인 프로그램에는 적합하지 않는 조인 방식이다.


column_img_1613.png

위 그림은 1,000쌍의 부부가 흩어져 있는 체육관에서 각자 배우자를 찾는 방법을 Hash Join 방식으로 설명한 것이다. 아무런 규칙 없이 모든 사람이 배우자를 찾고자 동시에 움직인다면 많은 시간이 소요될 것이다. 하지만 위의 그림과 같은 Hash Join 방식은 그러한 시간을 줄일 수 있다. 먼저 남자들이 본인 성씨 구역으로 집결하면, 여자들이 남편의 성씨 구역으로 가서 남편을 찾는다. 여기서 성씨 구역들은 해시 테이블을 의미하며, 성씨 분류는 해시 함수를 의미한다.

김씨를 남편으로 둔 여자들은 다른 여자들보다 찾는 시간이 더 많이 걸릴 것이다. 마찬가지로 Hash Join에서도 하나의 버킷(구역)에 많은 해시키(김씨들)가 존재할 때, 그만큼 액세스를 많이 해야 하므로 처리 시간이 늘어나서 성능이 떨어지게 된다.


column_img_1614.png

Hash Join 처리 순서는 다음과 같다.


1. 조직 테이블에서 사업부가 ‘강원사업부’인 조직들을 구한 후, 조인절 컬럼인 조직코드를 해시 함수로 분류한 다음, 해시 테이블을 생성한다.

(해시 함수를 이용해 해시 테이블 생성)

2. 집계 테이블에서 처리년월이 ‘201412’인 자료를 구한 후, 조인절 컬럼인 조직코드를 해시 함수로 변환 후 해시 테이블로 순차적으로 접근한다.

(해시 함수를 통해 해시 테이블 탐색)


Hash Join에서는 작은 테이블을 먼저 접근하는 것이 성능 면에서 더 좋다. 해시 테이블 구성 작업에 부하가 많이 발생하기 때문이다. 작은 테이블에 접근해 Hash 함수로 해시 테이블을 생성하고, 이후 큰 테이블에 접근해 Hash 함수를 통해 순차적으로 해시 테이블로 접근한다. 이러한 조인 방식은 대량 데이터를 처리하는 배치성 프로그램에 유용하게 사용된다.


오라클 조인 방식의 특징 비교

지금까지 오라클의 3가지 조인 방식인 Nested Loop Join, Sort Merge Join, Hash Join에 대해 알아보았다. 아래 표는 위의 3가지 조인의 장단점과 특징을 요약한 것이다.


column_img_1615.png

조인 방식과 조인 순서 결정하기

주어진 작업의 성격과 DB 환경에 따라 조인 방식을 결정해야 하며, 조인 방식을 결정했다면 성능에 영향을 미치는 조인 순서도 결정해야 한다. 이러한 일은 주어진 정보를 바탕으로 직관적이고 종합적으로 판단해, 능동적으로 수행해야 한다. 오라클 옵티마이저가 우리에게 제공하는 정보만을 맹신해서는 안되며, 단지 참고 정보로만 활용해야 한다. 조인절에 참여하는 테이블 수가 많으면 많을수록 점점 더 복잡하고 결정하기 곤란하지만, 우리 스스로 최선의 조인 방식을 결정하고 조인 순서를 정하는 노력을 게을리 해서는 안된다. 이번 연재 내용에 더해 다음과 같은 지난 연재 내용을 다시 한번 읽어보면 쉽게 이해할 수 있을 것이다.


07회: 누구도 알려주지 않았던 '오라클 인덱스 생성도'의 비밀

08회: 누구도 알려주지 않았던 '오라클 쿼리 작성의 비법‘

09회: 쿼리 최적화 및 튜닝을 위한 오라클 공정쿼리 작성법



다음 연재에서는 오라클 힌트절에 대해 자세히 알아 보겠다.


용기를 갖자
오라클 DB뿐 아니라 대부분의 DB 구성 알고리즘은 어느 날 ‘하늘에서 뚝 떨어져 새로 만들어진 것’이
아니라 실생활에서 이용되는 혹은 이미 상식 수준에서 인지되는 그런 보편적인 원리를 바탕으로
만들어졌으므로 쉽게 접근하고 이해할 수 있다. 서두에서 말했듯이 ‘레몬시장이론’을 상기하며
DB를 지레짐작으로 어려워하지 말고 용기를 내고 하나씩 터득해 나가기를 바란다.
이 글은 DB 전문가 수준의 이해를 요구하지는 않는다. 단지 DB에 대해서 더 친숙하고 더 쉽게
이해하고 접근하길 바랄 뿐이다. 이 글을 읽으면서 궁금하거나 의문 나는 점이 있으면,
댓글을 달아주실 것을 적극 바란다. 아무리 어렵고 힘든 일이더라고 ‘관계’와 ‘소통’으로
풀어나갈 수 있음을 다시 한 번 믿으며….



[지난 문제의 정답과 풀이]

원리를 이해하고 논리로 풀어가는, 쉬어가는 DB 문제



지난 연재에 출제한 ‘원리를 이해하고 논리로 풀어가는, 쉬어가는 DB 문제’에 대한 정답과 해설은
아래와 같다. 문제를 풀면서 DB 원리를 하나씩 배우고 이해할 수 있다.


column_img_1616.png

column_img_1617.png



[이번 호 문제]

원리를 이해하고 논리로 풀어가는, 쉬어가는 DB 문제



각 연재의 말미에 간단하면서도 재미있고 생각해 보는 문제를 출제하려 한다. 모든 문제는 DB의 원리를 이해할 수 있는 문제로 출제할 예정이다. 문제를 풀면서 DB 원리를 하나씩 배우고 이해할 수 있다. 정답과 그에 대한 설명은 다음 연재에서 한다.


column_img_1618.png