사전 데이터 모델링
개념

데이터 모델링

gabury1

담을 데이터를 무엇으로 나눌지 무엇으로 이을지 정하는 일입니다. 나눈 것마다 어떤 값을 적을지도 여기서 정합니다. 같은 요구사항을 놓고도 사람마다 다른 모델이 나옵니다.

상세

집을 지을 때는 벽을 어디에 세워 방을 나눌지, 방마다 무엇을 들일지, 방과 방을 어느 자리에서 문으로 이을지를 먼저 정합니다. 벽이 서면 살림이 그 배치에 맞춰 들어와 해마다 쌓입니다. 몇 해 살고 나서 벽을 옮기려면 그 방을 채운 살림까지 전부 들어내야 합니다.

데이터 모델링은 담을 데이터를 무엇으로 나눌지, 나눈 것마다 무엇을 적을지, 그것들을 무엇으로 이을지를 정하는 일입니다. 나누어 놓은 하나하나를 엔티티라고 부릅니다. 엔티티에 적히는 낱낱의 값이 속성입니다. 엔티티와 엔티티 사이의 이어짐이 관계입니다.

같은 요구사항을 놓고도 모델은 하나로 정해지지 않습니다. 무엇을 한 덩이로 볼지, 어디에서 끊을지가 갈립니다. 주문과 주문 항목을 따로 둘 수도 있습니다. 둘을 한 덩이로 볼 수도 있습니다. 데이터 모델링은 답을 계산해 내는 일이 아니라 여럿 중에서 고르는 일입니다.

고른 결과는 오래 남습니다. 데이터가 쌓이면 그 모양에 기대는 코드도 함께 늘어납니다. 그 뒤에 모델을 바꾸려면 이미 쌓인 데이터를 옮겨야 합니다. 그 코드도 같이 고쳐야 합니다. 그래서 되돌리는 비용이 나중일수록 커집니다.

배경

프로그램마다 저장할 파일 구조를 따로 정하면 같은 데이터가 여러 곳에 갈라져 앉습니다. 부르는 이름도 담는 단위도 프로그램마다 다르게 굳습니다. 프로그램을 고칠 때마다 저장 구조가 함께 흔들립니다. 읽는 쪽은 데이터가 파일 안에 어떤 순서로 놓여 있는지까지 알아야 값 하나를 꺼낼 수 있습니다.

그래서 데이터가 무엇인지를 그것을 쓰는 프로그램·저장 방식과 떼어 먼저 적어 둘 필요가 생겼습니다. 무엇을 다루는지를 한 번 적어 두면 프로그램이 여럿이어도 같은 것을 같은 이름으로 부릅니다. 저장 방식을 바꿔도 그 기록은 그대로 남습니다.

그 결과가 같은 데이터를 세 계층으로 나눠 적는 방식입니다. 무엇을 다루는지만 적는 개념 모델, 그것을 표와 열 같은 논리 구조로 옮긴 논리 모델, 실제 저장 방식과 접근 경로까지 정하는 물리 모델입니다. 계층을 갈라 두면 아래가 바뀌어도 위를 그대로 둘 수 있습니다.

flowchart TD
    A[개념 모델] --> B[논리 모델]
    B --> C[물리 모델]

갈래

무엇을 한 덩이로 볼 것인가가 축입니다. 잘게 나눠 참조로 잇는 쪽과, 함께 읽히는 것을 한 덩이에 담는 쪽 사이에서 갈립니다. 나누는 쪽은 같은 사실이 여러 곳에 되풀이 적히는 일을 줄입니다. 담는 쪽은 읽을 때 여기저기서 끌어모으는 일을 줄입니다.

잘게 나눠 외래키로 잇는 쪽

이 쪽은 담을 것을 여러 테이블로 나눠 둡니다. 나눠 놓은 것을 다시 잇는 자리에 외래키 제약이 옵니다. PostgreSQL 문서는 외래키 제약을 한 열의 값이 다른 테이블 어느 행에 나타나는 값과 일치해야 한다는 뜻이라고 적습니다. 같은 문서는 이것을 두 관련 테이블 사이의 참조 무결성을 지키는 일이라고 부릅니다. 이렇게 적어 두면 참조되는 테이블에 나타나지 않는 널 아닌 값으로는 행을 만들 수 없습니다. 어디에서 끊을지, 무엇으로 이을지가 이 쪽의 결정입니다.

문서·집계 지향 모델

MongoDB 문서는 데이터 모델링을 데이터베이스 안 데이터의 조직, 그리고 관련된 엔티티 사이의 연결이라고 적습니다. 이 쪽의 핵심 원칙은 함께 접근되는 데이터를 함께 저장한다는 것입니다. 같은 문서는 성능을 최적화하려면 애플리케이션의 데이터 접근 패턴에 맞춰 모델을 짜야 한다고 적습니다. 담기는 모양도 한 벌로 고정되지 않습니다. 한 컬렉션 안의 문서들이 같은 필드 집합을 가질 필요가 없습니다. 같은 필드의 데이터 타입이 문서마다 다를 수 있습니다.

한 덩이로 담기만 하는 것은 아닙니다. 발행사 정보를 책 문서 안에 임베드하면 같은 발행사 데이터가 책마다 되풀이 적힙니다. 문서는 되풀이를 피하려면 참조를 쓰라고 적습니다. 발행사 정보는 책과 다른 컬렉션에 두라고 적습니다. 참조를 어느 쪽에 둘지는 관계가 자라는 모양이 정합니다. 발행사당 책 수가 적은 경우, 그리고 그 늘어남이 제한적인 경우에 발행사 문서 안에 책 참조를 둡니다. 책 수에 한계가 없으면 그 방식은 변하는 배열, 자라는 배열을 만듭니다. 그래서 참조를 책 문서 쪽에 둡니다.

예시

PostgreSQL 의 cities 와 weather

SQL
CREATE TABLE cities (
        name     varchar(80) primary key,
        location point
);

CREATE TABLE weather (
        city      varchar(80) references cities(name),
        temp_lo   int,
        temp_hi   int,
        prcp      real,
        date      date
);

무엇으로 나눌지 무엇으로 이을지가 이 두 정의에 들어 있습니다. 도시와 날씨를 따로 나눕니다. 날씨 쪽의 city 가 도시 쪽의 name 을 참조합니다. 이렇게 적으면 cities 에 없는 도시의 날씨 행을 넣을 수 없습니다.

INSERT INTO weather VALUES ('Berkeley', 45, 53, 0.0, '1994-11-28');

ERROR:  insert or update on table "weather" violates foreign key constraint "weather_city_fkey"
DETAIL:  Key (city)=(Berkeley) is not present in table "cities".

문서는 이것을 참조 무결성을 지키는 일이라고 부릅니다. 같은 문서는 단순한 데이터베이스 시스템에서 이 일이 이런 식으로 구현될 것이라고 적습니다. 구현이 되기라도 한다면 그렇다는 단서를 붙입니다. 먼저 cities 테이블에 맞는 레코드가 있는지 들여다봅니다. 그런 다음 새 weather 레코드를 넣거나 물리칩니다. 문서는 그 방식에 문제가 여럿 있다고 적습니다. 매우 불편하다고도 적습니다. 외래키의 동작은 애플리케이션에 맞게 세밀하게 조정할 수 있습니다.

PostgreSQL 의 products 와 orders

SQL
CREATE TABLE products (
    product_no integer PRIMARY KEY,
    name text,
    price numeric
);

CREATE TABLE orders (
    order_id integer PRIMARY KEY,
    product_no integer REFERENCES products (product_no),
    quantity integer
);

기본키 제약은 한 열 또는 여러 열의 묶음을 행의 고유 식별자로 쓸 수 있다는 표시입니다. 그러려면 값이 고유해야 합니다. 널이어서도 안 됩니다. product_no integer UNIQUE NOT NULL 로 적은 것과 같은 데이터를 받습니다. 외래키 제약은 한 열의 값이 다른 테이블 어느 행에 나타나는 값과 일치해야 한다는 뜻입니다. 이렇게 적으면 products 에 나타나지 않는 널 아닌 product_no 값으로는 주문을 만들 수 없습니다.

MongoDB 의 patron 과 address

// patron document
{
  _id: "joe",
  name: "Joe Bookreader"
}

// address document
{
  street: "123 Fake Street",
  city: "Faketon",
  state: "MA",
  zip: "12345"
}

같은 데이터를 한 덩이로 담으면 이렇게 됩니다.

{
  _id: "joe",
  name: "Joe Bookreader",
  address: {
    street: "123 Fake Street",
    city: "Faketon",
    state: "MA",
    zip: "12345"
  }
}

주소 데이터는 이용자 정보와 함께 자주 조회됩니다. 애플리케이션이 질의 한 번으로 필요한 정보를 다 가져오게 하려고 주소를 이용자 문서 안에 임베드합니다. 앞의 관계형 예시와 나누는 자리가 다릅니다. 한쪽은 둘로 나눠 참조로 이었습니다. 이쪽은 한 문서 안에 넣었습니다.

MongoDB 의 publisher 와 book

{
  _id: "oreilly",
  name: "O'Reilly Media",
  founded: 1980,
  location: "CA"
}

{
  _id: 123456789,
  title: "MongoDB: The Definitive Guide",
  author: [ "Kristina Chodorow", "Mike Dirolf" ],
  published_date: ISODate("2010-09-24"),
  pages: 216,
  language: "English",
  publisher_id: "oreilly"
}

같은 문서 모델 안에서도 나누는 자리가 갈립니다. 발행사를 책 문서 안에 넣으면 발행사 이름·설립 연도·위치가 책마다 되풀이 적힙니다. 발행사 문서 안에 books: [ 123456789, 234567890, ... ] 처럼 책 목록을 두는 방법도 있습니다. 다만 발행사당 책 수에 한계가 없으면 변하는 배열, 자라는 배열이 생깁니다. 그래서 책 쪽에 publisher_id 를 두었습니다.

관련 항목

데이터 모델링을 이루는 기본 단위

엔티티 · 속성 · 관계 · 테이블 · 행 · 열 · 필드 · 데이터 타입

무결성을 지키는 제약

기본키 · 외래키 · 제약조건 · 참조 무결성 · 유니크 제약 · 식별자

물리 모델에서 함께 정의하는 객체

스키마 · 인덱스 · 뷰 · 구체화 뷰 · 시퀀스 · 외래 테이블 · 데이터베이스 클러스터

문서 지향 모델에서 쓰는 개념

컬렉션 · 임베디드 문서 · 문서 참조 · 다형 데이터 · 데이터 접근 패턴 · 성능

데이터를 조직하는 다른 방식

데이터베이스 · 관계형 데이터베이스 · 계층형 데이터베이스 · 객체지향 데이터베이스 · PostgreSQL · MongoDB

데이터 모델링이 거치는 처리 단계

개념 모델 · 논리 모델 · 물리 모델

다른 이름: data modeling · 데이터모델링