출제기준 세세항목: 데이터모델 개념 · 개체-관계(E-R)모델 · 논리적 데이터모델링 · 데이터베이스 정규화 · 논리 데이터모델 품질검증
데이터 모델은 현실 세계의 정보를 컴퓨터에 담을 수 있는 모양으로 단순화해 표현한 설계도입니다. 도서관이라면 책, 회원, 대출 중 무엇을 기록할지, 각각 어떤 정보를 가질지, 서로 어떻게 이어지는지를 정리합니다. 건물을 짓기 전에 도면을 그리듯, 데이터베이스를 만들기 전에 모델을 먼저 그립니다.
데이터 모델은 세 가지 구성 요소로 이뤄집니다. 구조(Structure)는 데이터 개체들과 그 사이의 관계가 어떤 모양인지를 나타냅니다. 연산(Operation)은 저장된 데이터를 처리하는 작업, 즉 데이터를 조회하고 바꾸는 방법에 대한 명세로, 데이터베이스를 조작하는 기본 도구가 됩니다. 제약 조건(Constraint)은 저장될 수 있는 데이터에 대한 논리적인 제한으로, '학번은 겹칠 수 없다', '나이는 0보다 크다' 같은 것입니다.
모델에 그리는 대상도 세 가지로 정리됩니다. 개체(Entity)는 기록하려는 대상(회원, 책), 속성(Attribute)은 개체가 가진 세부 정보(회원의 이름, 연락처), 관계(Relationship)는 개체끼리의 연결(회원이 책을 대출한다)입니다. 데이터 모델은 표현 수준에 따라 사람이 이해하기 쉽게 현실을 그린 개념적 데이터 모델(대표적으로 E-R 모델)과, 컴퓨터가 다룰 수 있는 구조로 옮긴 논리적 데이터 모델(관계형, 계층형, 네트워크형)로 나뉩니다.
데이터베이스는 다섯 단계를 거쳐 만듭니다. 요구 조건 분석 → 개념적 설계 → 논리적 설계 → 물리적 설계 → 구현 순서입니다. 앞 단계일수록 현실 업무에 가깝고, 뒤 단계로 갈수록 특정 DBMS 제품과 컴퓨터의 저장 구조에 가까워집니다.
요구 조건 분석에서는 사용자가 어떤 데이터를 어떻게 쓰려는지 모아 명세서로 정리합니다. 개념적 설계에서는 그 요구를 E-R 다이어그램 같은 개념 모델로 그려 개념 스키마를 만들고, 어떤 트랜잭션이 일어날지도 함께 정리합니다(트랜잭션 모델링). 이 단계는 어떤 DBMS를 쓸지와 상관없이 진행합니다.
논리적 설계에서는 개념 모델을 관계형 같은 특정 논리 데이터 모델의 구조로 바꿉니다. 관계형이라면 E-R 다이어그램을 테이블 구조로 옮기고 정규화로 이상 현상을 없애 논리 스키마를 완성합니다. 물리적 설계에서는 이 구조를 실제 DBMS 위에 어떻게 저장할지 정합니다. 저장 레코드의 양식, 인덱스 같은 접근 경로, 저장 공간의 배치를 정하며 응답 시간·저장 공간 효율·트랜잭션 처리량을 따집니다. 마지막 구현 단계에서 DDL로 실제 데이터베이스를 만듭니다.
E-R(Entity-Relationship) 모델은 1976년 피터 첸(Peter Chen)이 제안한 개념적 데이터 모델로, 현실을 개체와 관계로 나눠 그림으로 표현합니다. 이 그림을 E-R 다이어그램(ERD)이라고 합니다. 특정 DBMS에 묶이지 않아 사용자와 설계자가 함께 보며 이야기하기 좋습니다.
첸 표기법의 기호를 정확히 기억해 두세요. 개체는 사각형, 관계는 마름모, 속성은 타원으로 그리고 이들을 선으로 잇습니다. 기본키 속성은 이름에 밑줄을 긋습니다. 스스로는 구별되지 못하고 다른 개체에 기대어 존재하는 약한 개체는 이중 사각형, 여러 값을 가질 수 있는 다중값 속성은 이중 타원, 다른 속성으로 계산해 낼 수 있는 유도 속성(생년월일로 구하는 나이 같은 것)은 점선 타원으로 그립니다.
관계에는 몇 대 몇으로 이어지는지를 나타내는 대응 수(카디널리티)를 적습니다. 1:1은 사원과 사원증처럼 서로 하나씩, 1:N은 부서와 사원처럼 한쪽 하나에 다른 쪽 여럿, N:M은 학생과 과목처럼 양쪽 모두 여럿과 이어지는 관계입니다. 실무에서는 첸 표기 대신 선 끝을 새 발 모양으로 그려 '여럿'을 나타내는 정보공학(IE) 표기법도 많이 씁니다.
논리적 데이터모델링은 개념 모델을 실제 저장 구조에 가까운 논리 모델로 바꾸는 작업입니다. 오늘날에는 대부분 관계형 모델을 쓰므로, E-R 다이어그램을 테이블(릴레이션)로 옮기는 일이 중심이 됩니다. 참고로 계층형 모델은 데이터를 부모-자식의 트리 구조로, 네트워크형 모델은 그래프(망) 구조로 표현하는 방식입니다.
옮기는 기본 규칙은 이렇습니다. 개체는 테이블이 되고, 속성은 열이 되며, 식별자는 기본키가 됩니다. 1:N 관계는 N쪽 테이블에 1쪽 테이블의 기본키를 외래키로 넣어 표현합니다. 부서와 사원이라면 [사원] 테이블에 부서번호 열을 둡니다. 1:1 관계는 둘 중 한쪽에 상대의 기본키를 외래키로 넣습니다.
N:M 관계는 외래키 하나로 표현할 수 없습니다. 학생 한 명이 여러 과목을 듣고 과목 하나를 여러 학생이 들으니, 어느 쪽에 외래키 하나를 넣어서는 다 담지 못합니다. 그래서 [수강]처럼 두 테이블의 기본키를 모두 외래키로 가져와 함께 기본키로 삼는 별도의 테이블을 만들어, N:M을 1:N 두 개로 풉니다. 성적처럼 관계 자체가 가진 속성은 이 테이블의 열이 됩니다.
부모의 기본키가 자식 테이블의 기본키 일부가 되는 관계를 식별 관계, 자식의 일반 열(외래키)로만 들어가는 관계를 비식별 관계라고 합니다. [주문]과 [주문상세]처럼 부모 없이는 자식이 의미가 없으면 식별 관계로, [부서]와 [사원]처럼 자식이 따로 구별될 수 있으면 비식별 관계로 두는 경우가 많습니다. 다중값 속성은 별도 테이블로 떼어 내 한 칸에 여러 값이 들어가지 않게 합니다.
한 테이블에 여러 주제의 정보를 섞어 두면 데이터를 다룰 때 뜻하지 않은 문제가 생깁니다. 이를 이상 현상(Anomaly)이라고 합니다. 기본키가 (학번, 과목코드)인 [수강신청(학번, 이름, 과목코드, 과목명)] 테이블을 생각해 봅시다. 삽입 이상은 새 정보를 넣으려는데 원하지 않는 다른 값까지 있어야 해서 넣지 못하는 문제로, 아직 아무도 신청하지 않은 새 과목은 학번이 없어 등록할 수 없습니다. 삭제 이상은 한 정보를 지웠더니 지우고 싶지 않은 정보까지 함께 사라지는 문제로, 어떤 과목의 유일한 신청자가 취소하면 그 과목 정보도 사라집니다. 갱신 이상은 같은 정보가 여러 행에 중복되어 있어 일부만 고쳐지면 값이 서로 어긋나는 문제입니다.
이상 현상은 속성 사이의 함수 종속을 따지지 않고 한 테이블에 몰아넣었기 때문에 생깁니다. 함수 종속은 X 값을 알면 Y 값이 하나로 정해지는 관계로, X → Y라고 쓰고 X를 결정자, Y를 종속자라고 부릅니다. 학번을 알면 이름이 하나로 정해지므로 학번 → 이름입니다.
함수 종속은 세 종류를 구별해야 합니다. 완전 함수 종속은 Y가 X 전체에 종속되고 X의 일부만으로는 정해지지 않는 경우입니다. 부분 함수 종속은 기본키가 여러 속성으로 이뤄졌을 때 Y가 그중 일부에만 종속되는 경우로, 앞의 테이블에서 과목명은 과목코드만으로 정해지므로 기본키에 부분 함수 종속입니다. 이행적 함수 종속은 X → Y이고 Y → Z여서 X → Z가 성립하는 경우로, Z가 X에 직접이 아니라 Y를 거쳐 종속된 것입니다.
정규화(Normalization)는 함수 종속을 따져 테이블을 주제별로 나눠, 중복을 줄이고 이상 현상을 없애는 과정입니다. 나눈 테이블들을 다시 조인하면 원래 정보가 그대로 복원되어야 하고(무손실 분해), 원래 있던 함수 종속도 되도록 잃지 않아야 합니다. 정규형은 단계가 올라갈수록 조건이 엄격해지며, 높은 정규형은 그 아래 단계의 조건을 모두 만족합니다.
제1정규형(1NF)은 모든 속성 값이 원자값인 상태입니다. 한 칸에 여러 값이 들어 있으면 행을 나누거나 별도 테이블로 뗍니다. 제2정규형(2NF)은 1NF이면서 부분 함수 종속을 없애, 기본키가 아닌 모든 속성이 기본키 전체에 완전 함수 종속된 상태입니다. 앞의 [수강신청]이라면 과목명을 [과목(과목코드, 과목명)]으로, 이름을 [학생(학번, 이름)]으로 떼어 냅니다. 제3정규형(3NF)은 2NF이면서 이행적 함수 종속을 없앤 상태입니다.
BCNF(Boyce-Codd 정규형)는 3NF를 더 엄격하게 한 것으로, 모든 결정자가 후보키여야 합니다. [수업(학생, 과목, 강사)]의 기본키가 (학생, 과목)이고 강사 한 명은 한 과목만 맡는다고 해 봅시다. 그러면 강사 → 과목이 성립하는데 강사는 후보키가 아니므로 BCNF가 아닙니다. [담당(강사, 과목)]과 [수업(학생, 강사)]으로 나눠야 BCNF가 됩니다.
제4정규형(4NF)은 BCNF이면서 다치 종속(한 속성 값에 다른 속성 값 여러 개가 서로 독립적으로 딸려 있는 관계)을 없앤 상태이고, 제5정규형(5NF)은 4NF이면서 후보키를 통하지 않는 조인 종속을 없앤 상태입니다. 다만 정규화를 지나치게 하면 테이블이 잘게 쪼개져 조회할 때마다 조인이 늘고 성능이 떨어질 수 있습니다. 그래서 물리 설계 단계에서 성능을 위해 일부러 정규화를 되돌리는 반정규화를 검토하기도 합니다.
논리 모델을 다 그렸다면 다음 단계로 넘기기 전에 품질을 점검합니다. 이 단계에서 놓친 잘못은 테이블이 만들어지고 프로그램이 짜인 뒤에는 고치기가 훨씬 어렵기 때문입니다. 점검은 보통 업무 담당자, 설계자, 데이터 관리자가 함께 모델을 읽으며 검토하는 방식으로 진행합니다.
점검하는 관점은 이렇게 정리할 수 있습니다. 업무 규칙과 요구사항을 빠짐없이 담았는지(완전성), 업무 내용과 데이터 정의가 정확히 맞는지(정확성), 명명 규칙과 표준 용어, 자료형 표준을 지켰는지(준거성), 같은 데이터가 여러 곳에서 다르게 정의되지 않았는지(일관성), 최근 바뀐 업무가 반영됐는지(최신성), 사용자가 이해하고 활용하기 쉬운지(활용성)를 봅니다.
구체적으로는 모든 개체에 식별자(기본키)가 있는지, 관계의 대응 수와 필수·선택 여부가 업무와 맞는지, 정규화가 알맞은 수준까지 되었는지, 같은 뜻의 속성이 다른 이름으로 중복되지 않았는지, 속성마다 도메인과 자료형이 정해졌는지를 확인합니다. 업무 프로세스가 각 개체를 생성(Create)·조회(Read)·수정(Update)·삭제(Delete)하는지를 표로 그린 CRUD 매트릭스로, 아무 프로세스도 쓰지 않거나 만들어 주는 곳이 없는 개체를 찾아내기도 합니다.
동아리 관리 앱을 만들며 학생과 동아리를 개체로, '가입한다'를 관계로 그렸습니다. 학생 한 명이 여러 동아리에, 동아리 하나에 여러 학생이 가입하니 N:M 관계입니다. 테이블로 옮길 때 [가입(학번, 동아리번호, 가입일)] 테이블을 따로 두고, 관계가 가진 속성인 가입일을 그 테이블의 열로 넣었습니다.
[고객(고객번호, 이름, 등급코드, 할인율)]에서 할인율은 등급코드에 따라 정해졌습니다. 고객번호 → 등급코드 → 할인율인 이행적 함수 종속이라, 등급별 할인율을 바꾸려면 그 등급의 고객 행을 모두 고쳐야 했고 하나라도 빠지면 갱신 이상이 생겼습니다. [등급(등급코드, 할인율)]을 따로 떼어 3NF로 만들자 할인율 변경이 한 행 수정으로 끝났습니다.
논리 모델 검토 회의에서 [회원]의 '연락처'와 [주문]의 '전화번호'가 같은 뜻인데 이름과 길이가 다르게 정의된 것을 찾아 표준 용어와 자료형으로 통일했습니다. 또 CRUD 매트릭스를 그려 보니 [쿠폰] 개체를 만들어 주는 프로세스가 없어서, 업무 담당자와 쿠폰 발급 절차를 추가로 정리했습니다.