Programming/SQL

INNER 조인,outer 조인, 관계형 데이터 베이스. 2021-08-11

최동훈1 2021. 8. 11. 16:40

우선 DBMS가 발달하기 전에는 데이터베이스중 일부 칼럼이 중복되더라도 각 각 다른곳에 저장했다. 그런데 단점은, 메모리가 너무 많이 잡아먹는 다는 것이고 결함, 실시간 씽크 등의 무결성 측면에서 문제가 되기 때문에, 공통의 부분은 잘라내고 꼭 필요한 부분만 잘라서 따로따로 DBMS가 관리해주기 시작했다. 이것은 내 오라클 첫 포스트에도 설명했던 관계형 데이터베이스의 탄생 내용이다. 이렇게 각각 따로 나누어서 공통된 부분을 서로 참조관계로만 묶여있던 테이블들을 테이블들을 원래대로 합치는 기능을 하는 것이 바로 조인(join) 이다.

 

간단하게 그림으로 보여주자면,

ID 생년월일 글쓴이. 내용,
최동훈 000.131 최동훈 jdbc의 이해...
최동훈 000.131 최동훈 헬스장을 갔다.....
최동훈 000.131 최동훈 서울에 서 숙소에서 묶고...
최.훈 870204 최.훈 오늘의 공부는?

 원래라면 이렇게 ID 의 인적사항과 글쓴이를 매치시켜서, 중복되는 내용이 함께 저장이 되었다면, 이제는 오른쪽 칼럼 중 '글쓴이' 를 부모 테이블을 찾는 '키'로써 활용하고 중복된 것을 제거해서 따로따로 저장하고, 필요할때마다 찾아서 합치는 방법을 쓴다. 왜냐하면, 저장공간의 크기를 아낄수 있고, 단순히 복사해서 합치는 과정은 메모리 상에서 큰 비용을 쓰는 일이 아니기 때문이다. 오히려 처음처럼 저렇게 방대한 레코드들을 디스크에서 찾아오는게 더 비용이 많이든다.

ID 생년월일
최동훈 000131
최.훈 870204

 

글쓴이 내용
최동훈 jdbc의 이해....
최동훈 헬스장에서 운동을 하는데...
최동훈 서울에서 숙소에 묶고...
최.훈 오늘의 공부는?

즉, 이렇게 두 테이블을 따로따로 저장한다음 필요할때마다, 글쓴이를 KEY 로써 부모테이블의 ID를 기준으로 매치시킨다. 이렇게 쓰는게 I/O 과정을 단축 시키고 메모리를 효율적으로 쓸수 있다.

 

내가 오늘 배운 내용은 이 두 테이블을 합치는 쿼리이다. 위 두 테이블을 사례로 들어보면,

select * from member  inner join notice on member.name=notice.writer_id;

이 쿼리를 쓴다면 두 테이블을 "최동훈","최.훈"을 기준으로 인적사항과, 글 내용을 합칠 수 있다.

실행결과.

원래대로 라면.

이렇게 인적사항만 별도로 저장된 'member' 라는 테이블과  글 내용이 분리되어 있었따.

이런 두 테이블을 member 테이블을 부모테이블로 하여, NAME 과 WRITER_ID를 기준으로 합친 것이다.

또한 INNER join 이라는 표현은 각각 자식 테이블의 '키'에 매치되는 레코드만 합친다는 의미이다. 내 사례에서는 없지만 만약 인적사항을 저장한 테이블 중, '최훈훈' 이라는 이름의 인적사항이 있으면 그것은 OUTTER 레코드 로 불리고, inner join 시에는 합쳐지지 않는다.

 

또 내가 방금 쓴 쿼리는 ANSI SQL 이라고 모든 DBMS에서 쓸수 있는 표준적인 이너 조인 쿼리문이다.

 

그런데 문제가 있다. 애초에 기준이되는 member 테이블의 name에 동명 이인이 너무 많아 다대다 연결이 되어 너무 복잡하게 결과가 나온다. 그래서 난 인적사항의 중복된 name을 줄여서 일대다 연결이 되도록 하였다. 또한 명확하게 글쓴이와 글 내용을 직접 사람이 쓴 것 같은 사례로 만들기 위해 notice 테이블도 손보았다.

새롭게 바꾼 notice 테이블(진짜 게시판에 글쓴 것 처럼 보이게 만들었다.)
새롭게 바꾼 member 테이블(중복되는 name을 없앤 인적사항 member 테이블을 다시 만들었다.)

 

이렇게 되면 내가 맨 처음 설명한 표 와 같은 조인을 성립시킬수 있다.

select * from member as m inner join notice as n on m.name=n.writer_id;

이러면 깔끔하게 일대 다 연결로 나온다. 

그럼 OUTTER 조인은 무엇일까?  바꾼 member table 에서는 '최명자',와 '후니' 라는 이름을 가진 테이블들은 자식 테이블인 notice의 키에서 매치되지 못했기에, outter 가 되어서 아예 연결되지 못했다.

그런데 이런 outter들을 연결시킬려면 outter join 쿼리를 쓰면 되고, left / right / full 키워드를 통해, 어느쪽 테이블의 outter을 포함시킬건지 정할 수 있다. 직접 예를 들어 보이겠다. 만약 왼쪽 테이블의 outter를 포함시키고자 한다면,

select m.name,m.id,n.writer_id from member m left outter join notice n on m.name=n.writer_id;
--from 절에서 별칭을 각각 member는 m, notice는 n으로 붙임.

 이러면 된다.

 

 

기존엔 자식 테이블에 매치되는 키가 없어서 연결되지 못했던 outter 들이 연결되었다.

 

이번엔 오른쪽 테이블의 outter들을 추가하려면

select m.name,m.id,n.writer_id,n.content from member m right outer join notice n on m.name=n.writer_id;
--from 절에서 별칭을 각각 member는 m, notice는 n으로 붙임.

notice에서는 빠져있었던 outer 레코드가 추가되었다.

 

** 부모테이블과 자식 테이블을 구별하는 기준은 쿼리의 왼쪽, 오른쪽 배치 순서와 상관 없고, 일 대 다 연결에서 '일' 인쪽이 부모테이블이 되고, '다' 인 쪽이 자식 테이블이 된다.

 

공부시간 3시간.

순공시간 2시간.

 

오늘은 나름 코딩을 직접 해보며 공부를 해서 그런지 공부가 잘 되었다. 특히, 이런 관계형 DB 구조가 만들어진 원리를 이해하니 뿌듣하다. 게다가 member 테이블과 notice 테이블을 계속 고쳐가며 어떻게하면 쉽게 설명이 되고 직관적으로 이해가 될까? 라는 고민을 하면서 공부하니 더욱 더 개념이 잘 체화되는거 같다. 역시 남을 가르치기위한 공부가 진정한 공부인거 같다.