ODBC(Open Database Connectivity) ?


오늘은 DBMS와 통신을 할 때 흔히 사용하는 ODBC에 대해 정리해보겠다.


먼저 ODBC의 정의는 데이터베이스에 접근하기 위한 소프트웨어의 표준 규격이다.


이렇게 정의만 보고서도 "아~ 그러쿠나" 하는 천재가 아니니까 나는.

왜, 뭘 위해 이런 규격이 있는건지 알아보겠다.


1. 소켓 통신

응용프로그램은 DBMS와 데이터를 주고 받는 통신이란 것을 한다.


이 말은 응용 프로그램 상에서 실행 중인 프로세스와, DBMS에서 실행 중인 프로세스가 서로 통신을 한단 얘기다.


이렇게 프로세스와 프로세스 사이에 데이터를 주고 받는 방식은 여러가지가 있는데, 가장 기본적인 방식이 바로 "소켓 통신"이다.


소켓 통신 방법은 대략 이렇다.

소켓을 생성해서 연결을 한 다음, 어떤 형식으로 데이터를 주고 받을 것인지 '프로토콜'에 따라 주고 받는다. 끗.


그럼 이렇게 하면 되잖아?? 

그런데 문제는 DBMS사마다 프로토콜이 다르다.


그래서 불쌍한 개발자들은 프로그램을 각 DBMS사에 맞춰서 따로따로 개발해야 하지만..

100번 양보를 해서 따로따로 개발한다 치자.


그런데 더 큰 문제는 DBMS사에서 프로토콜을 공개하지 않는다는 점.


왜냐? 프로토콜도 중요한 기술력이니까.

DBMS사의 입장에서는 어떤 기술을 이용해야 통신이 빠른지 이런 것들이 다 기술력이니 프로토콜을 공개할 리 만무하다.


2.  Vender API를 통해 통신

그래서 우리의 DBMS사에서는 자기네 프로토콜을 공개하지 않으면서 응용프로그램과 통신하는 방법으로 자기네 DBMS와 통신할 수 있는 API를 제공한다.


덕분에 개발자 입장에서는 소켓 통신 개발을 할 필요가 없고,

MS-SQL DBMS랑 통신하려면 MS-SQL API, MySQL이랑 통신하려면 MySQL API를 이용하면 된다. 


이 API를 통해 호출하면 얘네들이 각각 자기네 DBMS랑 프로토콜로 통신한다. 


근데 얘도 똑같은 문제가 있는데, DBMS마다 API사용법이 다르다는 점이다.


결국엔 DBMS마다 각각 다른 프로그램을 개발해야 한다는 불편함은 여전히 존재한다.




3. ODBC API를 통해 통신

이런 젼차로 어린 개발자가 제 뜻을 시러펴디 못할까하여 MS사가 잔머리를 굴려 내놓은게 ODBC API 규격이다.


ODBC는 데이터베이스에 접근하기 위한 표준 규격으로, 모든 DBMS에 접근하는 방법을 통일시켰다.


이 규격에 따라서 DBMS는 자기네 Vender API에 접근하여 조종하는 "ODBC Driver"라는 것을 만들어 제공한다.


MySql ODBC Driver, Oracle ODBC Driver, MS-SQL ODBC Driver가 각각 다 있다 그 말.

(Excel ODBC Driver도 있음!)



ODBC !


 ODBC 규격        

MySQL ODBC Driver            

MySQL Vender API               

MySQL DBMS

Oracle ODBC Driver              

Oracle Vender API                

Oracle DBMS



특징 하나) DBMS 비종속적이다!


위에서 말했듯, ODBC는 "표준 규격"이다.


즉, ODBC는 모든 DBMS의 기능을 다룰 수 있어야 한다.


따라서 ODBC는 온갖 종류의 DBMS의 모든 기능들을 다 가지고 있다.


그래서 개발자는 ODBC API에 맞춰서 프로그램을 개발하고, 어떤 DBMS를 쓸지 결정만 하면된다. 

저 DBMS나 이 DBMS나 어차피 똑같은 코드를 사용하니까.


그.러.나 주의할 것은,

ODBC에 정의된 함수라고 해서 모든 DBMS에서 사용 가능한 것이 아니다.


즉, ODBC Driver라고 해서 ODBC API에 정의된 모든 기능이 있는 것이 아니다. 

ODBC Driver는 해당 DBMS가 지원 가능한 기능만 만들었기 때문이다.


그치만,

어쩌다가 MySQL에만 있는 기능을 썼는데 Oracle DBMS와 통신해야 한다면 그 부분만 조건문으로 처리해서  다른 방향으로 호출하면 될 것이다.

이전처럼 완전히 따로 작성하는 것보다 간단하다.

고객사 입장에서도 DBMS 선택에 있어서 이전보다 자유로울 수 있다. 

Oracle사를 썼다가 다른 DBMS로 갈아타기가 이전보다 수월해졌다는 얘기, 그들의 갑질에서 벗어날 수 있다는 말씀.




특징 둘) 속도가 느리다.


ODBC Driver를 이용하면 Vender API를 직접 사용하는것보다 느리다.


그러나 충분히 DBMS 비종속적이라는 것만으로도 큰 이점이 있다.



  1. 악오 2017.05.31 09:22

    빨리 오세요

5. 제 3 정규화

어떤 컬럼이 PK가 아닌 다른 일반 컬럼에 종속되는 경우가 있다면, 별도의 테이블을 부모-자식 관계로 만든다.


이렇게 문장으로만 보면 뭔 말인지 이해가 안가니 예제를 통해 설명하겠다.

이 '학생'테이블을 잘 살펴보면 컬럼들 중에 반드시 '학생'에 종속되는 속성이 아닌 것이 있다.

바로 '우편번호'와 '기본주소' 컬럼이다.

기본주소만 놓고 보면, 학생에 따라 기본주소가 다르니 학생에 종속된 것은 맞다.
그러나 '우편번호' 컬럼이 있으면 얘기가 달라진다.


우편번호는 '학생이 누구냐'에 따라 달라지기 보다는, '기본주소가 어디냐'에 따라 달라지기 때문,

'기본주소'에 종속되기 때문이다.

그러나 상세주소는 우편번호나 기본주소가 어디냐에 따라 달라지지는 않는다.
아래 표를 보면 이해가 빠를 것이다.


학생 

 우편번호

 기본주소

상세주소 

 강동원

11111 

서울시 동대문구 장안동 

 100번지

 손석희

11111

서울시 동대문구 장안동 

 200번지

 김수현

 33333

경기도 이천시 부발읍 아미리 

 100번지


- 강동원 학생과 손서키 학생은 모두 장안동에 살지만, 상세주소는 다르다.

- 김수현 학생은 경기도 이천시에 살지만 서울시 동대문구 장안동에 사는 강동원 학생과 상세주소는 같다. (100번지)

이처럼 기본주소는 우편번호에, 우편번호는 기본주소에 따라 달라지는 관계이므로 두 컬럼을 별도의 테이블로 뺀 후, '학생'테이블과 관계를 맺어주겠다. 아래처럼.



이 과정(제 3 정규화)은 PK가 여러 개의 컬럼으로 이루어진 경우에 유용하다.

이 과정에서 기억해야 할 것은 "모든 일반 컬럼은 반드시 주키(PK)에 종속되어야 한다" 라는 점이다. 

제 3 정규화와 제 2 정규화가 아주 헷갈리는데, 제 2 정규화에 대한 내용은 살짝 건너뛰었다.
나도 아직 조금 헷갈리는지라 ..ㅜㅜ

시간이 나면 다시 제대로 공부해가지고 정리해야겠다.

여하튼 제 3 정규화는 일반 컬럼이 모두 주키에 종속되고 있는지를 확인한다는 것을 확실히 알고, 이만 여기서 마무으리- 하겠다.
 
유후-



  1. bit 2017.04.27 23:52

    유용한 글이네요^^

4. 제 1 정규화 (중복 컬럼 해소)


앞 장에서 중복 데이터를 따로 빼서 테이블을 새로 정의한 후, 관계를 맺어주는 것을 해봤다.


그러나 제 1 정규화는 그게 끝이 아니라는 점.

테이블 안에 중복되는 컬럼들이 있으면 이놈들도 해결해줘야 한다.



1. 테이블에서 중복되는 컬럼들을 뽑아 별도의 테이블로 분리한다.    


이 테이블에서는 사진1, 사진2, ... 사진5 컬럼들은 모두 사진을 담는 컬럼이다.

교실마다 같은 사진을 가지고 있는 것도 아닌데 왜 중복된다는 건지..? 라고 생각할 수 있겠으나.


어떤 교실은 사진을 2장 가지고 있고, 또 어떤 교실은 5장 모두, 또 어떤 교실은 아예 사진이 없을 수도 있다.

마지막의 경우에는 컬럼이 낭비되는 셈이다. 


예를 들면.


 교실번호

교실명 

사진1

사진2

사진3 

 C01

 강동원교실

 




  C02

다니엘헤니교실







대략 이렇게 교실 테이블이 만들어질텐데, 강동원교실에는 사진이 1개밖에 없다.

때문에 사진2, 사진3 컬럼은 필요없는 컬럼인 셈이다.


이런 경우에도 중복되는 컬럼들만 빼서 별도의 테이블로 정의한다.


2. 새로 만든 테이블에서도 PK(주키)를 선정한다.




사진1 ~ 사진5 컬럼을 따로 빼서 '교실사진' 테이블을 만들었다.

그리고 '교실번호' 컬럼도 만들어줬는데, 얘는 해당 사진이 대체 어느 교실에 대한 사진인지 알아야하기 때문에 이렇게 만들어줬다.


이렇게 만들어주면 저기 위의 테이블이 이렇게 만들어질 것이다.


 교실번호

사진

 C01

 


 C02

  C02 

 

C02

 



이렇게 만들어진 테이블에는 더이상 낭비되는 컬럼따윈 없다.



그런데 각 행을 대표하는 식별자가 없어서 '교실사진번호' 라는 컬럼을 새로 만들어 주키로 선정해주었다. 

(사진을 주키로 삼으면 안되는 이유는 저기저기 앞에 있는 포스트에서..)


 교실사진번호

 교실번호

사진

 CP01

 C01

 


CP02

 C02

CP03

  C02 

 

CP04

C02

 


3. 새로만든 테이블과 기존 테이블간에 부모-자식 관계를 맺어준다.

기존의 '교실' 테이블과 새로 만든 '교실사진' 간에 관계를 맺어주면 아래와 같이 된다.





교실사진 테이블에 '교실번호' 라는 컬럼이 새로 생긴걸 확인할 수 있다. 

이 컬럼이 두 테이블이 관계를 맺고 있다는 사실을 알려주는 외래키(FK)이다.

(두 테이블 간 관계를 맺는 자세한 내용은 앞의 포스트를 확인할 것!)



이것으로 제 1 정규화는 끗.

관계 차수는 나중에..

 



3. 제 1 정규화

중복 데이터 또는 중복 컬럼(속성)을 별도의 테이블(엔티티)로 만들고, 기존 테이블과 관계를 맺어준다.

여기부터 이제 평화로웠던 디비나라에 격변이 일어나기 시작함...


말로만 보면 당최 뭔 말인지 모르겠으니 직접 한번 해보겠다.




먼저 앞의 엔티티, 속성, PK까지 정하는 과정을 거쳐서.. 아래처럼 테이블들이 나왔다. 

뭐 이건 어떤 시스템이냐에 따라(고객이 무엇을 원하냐에 따라) 달라질 수 있는 것들이다. 즉 노답임.



'강의' 테이블을 기준으로 순서대로 해보면.

1. 테이블에서 중복되는 데이터를 뽑아 별도의 테이블로 분리한다.    

이 테이블에서 '중복되는 데이터'를 뽑아내야 하는데 얼핏 보면 모르겠지만 다양한 데이터가 여러개 쌓이는 경우를 생각해보면 그렇지가 않다.

A라는 강의가 있을 때, 그 강의가 4월에 시작하고 5월에 끝나고, 또다시 6월에 개강할 수 있다.

그러면 아래처럼 테이블이 만들어질 것임.

 강의번호

강의명 

내용 

시작일 

종료일 

 LEC01

 A

데이터 모델링 

2017-04-20 

2017-05-20 

  LEC02

 A

데이터 모델링 

2017-06-01

2017-07-01 


전혀 문제가 없는 것 처럼 보이지만... 이렇게 되면 데이터의 중복이 발생한다. 

A강의는 강의명과 강의내용은 동일하지만, 시작일이 다르므로 서로 다른 '강의'로 취급된다는 점이다.

따라서 각각 다른 강의번호를 가지게된다.

이는 이후에 데이터를 관리할 때 번거로움과 어려움이 따를 수 있다.


 따라서 이런 경우에는 중복되는 데이터가 있는 것들만 따로 빼내서 별도의 테이블로 정의해야 한다.


2. 새로 만든 테이블에서도 PK(주키)를 선정한다.



위에서 강의명과 내용을 따로 뽑아서 '교육과정'이라는 테이블을 만들었다.

그러면 해당 테이블에서도 각각을 대표할 수 있는 식별자가 있어야 하는데, 강의명과 내용은 식별자(주키)로 사용하기에 적절하지 않으므로, 교육과정번호라는 임의의 컬럼을 만들어 주키로 선정했다.

(주키를 선정하는 방법은 이전 포스트에 있다능)


3. 새로만든 테이블과 기존 테이블간에 부모-자식 관계를 맺어준다.

기존의 강의 테이블과 새로 만든 교육과정 테이블은 서로 '관계'가 있다. 
교육과정 테이블은 중복된 데이터를 뽑아냄으로써 만들어진 테이블이라는 것만으로도 서로 관계가 있다는 것을 알 수 있다.

이럴 때, 두 테이블 간에 관계를 맺어주어야 하는데 아래와 같이 맺어주면 된다.


이렇게 엔티티(테이블)들을 선으로 연결시켜주면 된다.

고런데, '강의'테이블에 아까는 없었던 '교육과정번호'라는 컬럼이 생겼다.
이건 '교육과정' 테이블과 관계가 맺어지면서 만들어진 외래키(Foreign Key, FK, 참조키)라는 것이다.
외래키 이놈은 반드시 참조하고있는(관계를맺고있는) 교육과정 테이블에서 식별자 역할을 하는 unique한 컬럼만 될 수 있다.
보통  PK를 외래키로 참조한다.

근데 관계를 맺은것 까진 알겠는데...
교육과정 테이블에 '강의번호'라는 외래키가 들어갈 수도 있을텐데.
왜 꼭 강의 테이블에 '교육과정번호'라는 외래키가 생겼나 하는 의문이 들 것이다.
그건 누가 부모테이블이고 누가 자식테이블인지에 따라 달라진다.

강의 테이블에서 교육과정 테이블이 떨어져 나왔으니까 마치 교육과정이 자식테이블 같겠지만..
안타깝게도 그 반대다.

 교육과정

강의 

 교육과정번호

강의명 

내용 

 강의번호

시작일 

종료일 

 C01

 A

데이터 모델링 

 LEC01

2017-04-20 

2017-05-20 

 C01

 A

데이터 모델링 

 LEC02

2017-06-01

2017-07-01 


다시 이 표를 살펴보면, 
같은 교육과정 C01에 대하여 여러 강의가 개설될 수 있다.
하나의 자식이 여러 부모는 둘 수 없지만, 하나의 부모는 여러 자식을 가질 수 있다는 상식으로 접근하면 이해가 빠를 것임.


이렇게 관계까지 다 맺어주고 나면 관계 차수라는 것을 정해주어야 하는데, 이건 제3 정규화까지 진행한 후에 하는걸로 하게따.

끄읏-.

 



2. PK(Primary Key, 주키) 선정하기

각 엔티티(테이블)의 속성(컬럼)들 중에 바뀔 염려가 없으며, 해당 엔티티를 식별할 수 있는(중복되지 않는) 것을 주키(PK)로 선정한다.

이 때, 주키로 사용할만한 속성이 없는 경우에는 임의의 인공 컬럼(속성)을 새로 만들어서 주키로 사용한다.


그렇다면 어떤 경우에 인공 컬럼을 만들어 주키로 선정하는 것이 좋을까?

  • 향후 변경 가능성이 있는 속성을 주키로 사용하는 것은 바람직하지 않다.
    예를 들어, '학생' 테이블에서 '이메일' 속성은 향후 변경 가능성있다.
     있으므로 주키로 선정하기에 바람직하지 않다.



  • 주키로 사용할 속성에 들어갈 내용이 길어지는 것 또한 바람직하지 않다.
    예를 들어, '과목' 테이블에서 '과목명' 컬럼은 문자열이 길어질 가능성이 있으므로 임의의 인공 컬럼을 만들어 사용하는 것이 좋다..

    (주키는 주로 검색에 많이 이용이 되는데, 담고 있는 내용이 길어지면 그 속도가 느려질 수 있기 때문인듯)


대부분의 경우 인공 컬럼을 만들어 번호를 붙여 사용한다.


어떤 테이블의 경우는 두 개의 컬럼을 합쳐서 PK로 사용하기도 한다. 

다 대 다 관계 해소를 위해 새로 테이블을 만들어주는 경우나, 제 1 ~ 3 정규화를 통해 테이블을 따로 떼주면서 테이블 새로 만들어주는 경우 등에 

두 컬럼을 합쳐서 PK가 생기는 일이 발생하곤 한다.


모델링 초반엔 일어날 일이 거의 없으므로 생략하고 넘어가겠당. 




앞에서 정의한 내용을 바탕으로, 모델링을 순차적으로 진행해보겠다!


먼저 이 장에서 하게 될 엔티티와 속성을 정하는 과정은

가장 쉽지만 추상적이고 딱히 답이 없는..? 그런 과정이 되겠다.


하지만 여기서 정의하는게 개인적으로는 중요하고 또 중요하다고 생각한다.

여기서 이름 하나를 잘못 지어 놓으면, 속성을 정하거나 이후에 관계맺기를 할 때마다 헷갈리기 때문이다.

프로그래밍할 때 언제나 변수명 정하느라 멍 때리며 시간 보내는 나에겐 중요한 작업이당.


예제로 '수강관리 시스템'의 DB를 설계해보장! 

1. 엔티티 식별하기

우리가 다루는 정보들이 무엇인지 정의한다.

시스템에서 다룰 데이터들의 집합을 정의하는거라고 한다.

여기서 정해진 엔티티들은 DB에서 어떻게 사용되냐 하면, 각각 하나의 테이블을 이룬다.

그러니까 앞으로  '엔티티 = 테이블' <- 요런 공식을 적용해도 무방하겠다.


이렇게 말로만 보면 무슨말인지 모르겠으니 예를들어보자.
수강관리 시스템에서 우리가 다룰 정보들을 나열하면 교실, 강의, 과목, 강사, 학생, 매니저(한 강의에 대해서 관리하는 사람) 등이 있다.


요렇게.


참고로 앞장에서 말했듯, 저건 eXERD라는 툴을 이용했다.
Eclipse에다가 eXERD플러그 인을 설치해서 사용한건데 디비 모델링할때 유용하다.


여하튼.


엔티티를 정의하는 데에 있어서 중요한 것은, 고객이 원하는 정보가 무엇인지를 명확히 알아야 한다는 것이다.

엔티티 뿐만아니라 모델링하는 과정에서 이런 디비시스템을 의뢰한 고객과 자주 소통하며 어떤 시스템을 원하는지를 명확하게 알고, 서로 같은 그림을 그려야 이후에 고생하지 않는다.

따라서 이 과정에는 고객이 반드시 개입되어야 한다(고 한다).


2. 엔티티의 속성 식별하기

각 엔티티에 필요한 정보들을 정의한다.

엔티티를 정의한 후에는 속성을 정의하는데, 요 속성들은 테이블을 구성하는 값에 대응된다.

테이블의 '속성(attribute) = 컬럼(column)' <- 요렇게 알고 있으면 된다.


'강의'라는 엔티티의 속성에는 강의명, 내용, 시작일, 종료일 등의 정보가 정의될 수 있는데, 요놈들이 테이블에 들어 있는 컬럼들을 이룬다는 뜻이다.


요렇게.


엔티티명을 잘 지어야 속성에 어떤 값이 들어갈지 명확해지고, 중복되는 의미의 엔티티를 지어놓으면 컬럼을 만들때 산으로 간다.

그러니까 엔티티, 속성 정하는 과정을 너무 우습게 보면 큰 코 다친다는 말씀이다.



이런 식으로 각각의 엔티티에 대하여 모두 컬럼을 지정해주면 끄읓-이 난다.





모델링?

모델링은 현실세계를 모형화(추상화)하여 어떤 규칙을 가지고 모델을 만들어가는 것을 말한다. 


복잡한 현실세계의 일부를 단순화(?) 시키는 것이라고 하는데, 사실 '모델링은 이것이다' 하고 정의한 내용을 보면 감이 잘 오지 않는다.

모델링을 언제, 어떻게 하는건지 그 과정을 통해 이해하는게 훨씬 빠르다는게 내 생각이다.


데이터 모델링

데이터 모델링은 DB 설계에 이용된다.(현실세계를 데이터베이스화하는 데에 이용된다.)

일단 DB 설계 과정이 [요구분석 -> 개념적 설계 -> 논리적 설계 -> 물리적 설계 -> 구현] 순서로 이루어지는데,


이 중 '개념적 설계' 단계에서 개념적 데이터 모델링을 한다. 이 때 E-R 모델링을 하게된다.
현실세계를 글로 잘 옮겨다가 먼저 요구명세서를 만들고, 이 요구명세서의 내용들을 ERD로 표현하는 작업이 이 단계에서 이루어진다.
E-R 모델(Entity-Relationship Model)은 데이터 모델의 표기법이다.
(1976년에 피터첸이라는 사람이 이 표기법을 만들었다고 한다. 피터첸 피터첸,)
이 표기법은 직관적인 그림?을 통해서 엔티티, 속성, 관계를 파악할 수 있게 해주는 유용한 친구다.

E-R 모델링을 통해 개념적으로 포괄적인 수준의 모델링이 완료되었다면, 그 내용을 가지고 논리적 설계, 즉 논리적 데이터 모델링을 진행한다.
이 단계가 데이터 모델링의 핵심이라고 할 수 있다.
시스템 구축을 위해서 우리가 결정해야 할 대부분의 사항을 기초적인 부분부터 대부분의 것들을 모두 정의하는 과정이다.
개념적 데이터 모델링의 추상적인 것들을 논리적인 구조와 규칙을 명확하게 표현하는 과정이라 할 수 있다.
이 단계에서는 '정규화(Normalization)'가 진행되는데, 이게이게.. 어렵고 중요하다.
정규화는 논리 데이터 모델링의 아주 대표적인 활동인데, 논리 데이터 모델의 일관성을 확보하고 중복을 제거하는 등... 하여튼 매우매우 중요하다!
모델링 과정에서 자세히 다루겠다.

그 다음으로 물리적 데이터 모델링이 이뤄지는데, 논리 데이터 모델을 어떻게 컴퓨터의 H/W에 표현할 것인가를 다룬다.
테이블, 컬럼 등이 표현될 물리적인 저장구조, 데이터에 접근하는 방법 등을 이 단계에서 정의한다.




여기까지는 이론이었고.
실무에서는 개념적 데이터 모델링과 논리적 데이터 모델링을 한꺼번에 수행하는 것이 대부분이라고 한다.

다음 장부터는 실무의 방법으로 데이터 모델링을 하는 방법을 소개해볼까 한다! 헿
* 사용할 툴: Eclipse(Mars) + eXERD



* Reference: http://www.dbguide.net/db.db?cmd=view&boardUid=148404&boardConfigUid=9&categoryUid=216&boardIdx=132&boardStep=1

+ Recent posts