백엔드 데이터 인프라 7편 — PostgreSQL 관계형 모델 핵심 개념

2026-05-17백엔드 데이터 인프라

백엔드 데이터 인프라 7편. PostgreSQL의 토대인 관계형 모델 — 행·열·관계·기본 키·외래 키 핵심 개념을 풀어쓴 학습 노트.

📚 백엔드 데이터 인프라 · 7편 — PostgreSQL 관계형 모델 핵심 개념

이 글은 백엔드 데이터 인프라 시리즈 70편 중 7편이에요. 6편 접속 까지 "환경" 을 만들었으니, 이번 7편은 그 위에 "데이터를 어떻게 표현하느냐" 의 핵심 — 관계형 모델 의 기본 개념.

왜 입문에서 이 개념을 다시?

자바 백엔드 입문 시리즈에서 JPA·@Entity·Repository를 다뤘다면 — "테이블·행·열" 이 이미 익숙할 거예요. 다만 PG 깊이로 가려면 — 관계형 모델의 "왜 이렇게 설계됐는지" 한 번 정리하고 가는 게 도움. 8편 SQL 기초·9편 CREATE TABLE 부터는 이 개념 위에 직접 코드를 박아요.

관계형 모델의 기원

관계형 모델 = 1970년 IBM 연구원 Edgar F. Codd 가 제안. "데이터를 수학적 관계(relation, 즉 표) 로 표현하자" 라는 단순하지만 강력한 아이디어. 50년+ 지난 지금도 RDBMS의 토대.

핵심 4가지: - 데이터는 테이블 로 - 테이블 = (row) + (column) - 행 = 한 개체의 사실 - 행 사이 관계 = 외래 키로

테이블 — 한 종류의 사실 묶음

+----+----------+-------------------+---------------------+
| id | name     | email             | created_at          |
+----+----------+-------------------+---------------------+
|  1 | Alice    | alice@example.com | 2026-05-17 10:00:00 |
|  2 | Bob      | bob@example.com   | 2026-05-17 10:05:00 |
|  3 | Charlie  | NULL              | 2026-05-17 10:10:00 |
+----+----------+-------------------+---------------------+

"users 테이블" 이 표현하는 것 = "우리 시스템의 사용자들". 한 행 = 한 사용자.

용어: - 테이블(table) = 관계(relation) 또는 엔티티 집합 - 행(row) = 튜플(tuple) 또는 레코드 - 열(column) = 속성(attribute) 또는 필드

논문에선 "관계·튜플·속성" 이라 부르지만 — 실무에서는 "테이블·행·열" 이 압도적.

열 = 도메인 + 타입

각 열은 "무엇을 담느냐" 가 명확.

타입 의미
id BIGINT 사용자의 고유 식별자
name TEXT 이름 (한 사람)
email TEXT 이메일 (필수 X — NULL 허용)
created_at TIMESTAMPTZ 가입 시각

타입 = "이 열이 받을 수 있는 값의 범위". 32편 데이터 타입에서 PG 풍부한 타입을 깊이.

행 = 한 개체의 사실 묶음

한 행이 "한 개체" 를 의미. 한 행의 모든 열을 합치면 — "이 사용자에 대해 우리가 아는 모든 것".

원자성 (Atomicity, 한 셀에 하나의 값) — 한 셀(행과 열의 교차점) 에는 "단일 값" 만. 예: tags 열에 "red,blue,green" 같은 콤마 분리 값 박는 건 안티패턴.

❌ 나쁜 예
+----+--------------------+
| id | tags               |
+----+--------------------+
|  1 | red,blue,green     |
+----+--------------------+

✅ 좋은 예 (별도 테이블)
+----+-------+         +------+----------+
| id | name  |         | uid  | tag      |
+----+-------+         +------+----------+
|  1 | Alice |         |  1   | red      |
+----+-------+         |  1   | blue     |
                       |  1   | green    |
                       +------+----------+

"정규화" 원칙이 관계형의 핵심.

기본 키 (Primary Key)

행을 "고유하게 식별" 하는 열. 한 테이블에 1개.

CREATE TABLE users (
    id      BIGSERIAL PRIMARY KEY,    -- 자동 증가 + 기본 키
    name    TEXT NOT NULL,
    email   TEXT UNIQUE
);

기본 키 후보: - 자동 증가 정수 (BIGSERIAL·IDENTITY) — 가장 흔함 - UUID (Universally Unique Identifier, 충돌 없는 식별자) — 분산 시스템 표준 - 자연 키 (이메일·주민번호 등) — 위험 (변할 수 있음)

자연 키는 "바뀔 수 있는 데이터" — 추천 X. 인공 키(자동 증가 또는 UUID) 가 안전.

외래 키 (Foreign Key)

다른 테이블의 기본 키를 "참조" 하는 열. 행 사이 관계 표현.

CREATE TABLE orders (
    id         BIGSERIAL PRIMARY KEY,
    user_id    BIGINT NOT NULL REFERENCES users(id),
    amount     INTEGER NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

user_id 가 — users.id 를 가리키는 외래 키. "이 주문은 어느 사용자의 것인가" 가 명확.

이게 참조 무결성 — DB가 "존재하지 않는 사용자 ID로 주문 만들기" 를 거부.

INSERT INTO orders (user_id, amount) VALUES (999, 10000);
-- ERROR: insert or update on table "orders" violates foreign key constraint

자바 백엔드 입문 46편 JPA 연관관계 가 자바 객체 ↔ 이 외래 키 매핑.

NULL — "값이 없음" 의 특별한 상태

SELECT email FROM users WHERE id = 3;
 email
-------
 NULL    ← 값이 없음 (모름·미입력)

NULL 의 핵심 룰: - NULL = NULL참(true) 이 아님NULL - WHERE email = NULL ❌ — 항상 거짓 - WHERE email IS NULL ✅ — 표준 - WHERE email IS NOT NULL ✅ - COUNT(email) = NULL 빼고 카운트 - COUNT(*) = 모든 행 포함

NULL 다루기가 SQL 입문자의 첫 함정.

1:1 · 1:N · N:M 관계

행 사이 관계 3가지.

1:1 — 한 사용자 ↔ 한 프로필

CREATE TABLE user_profiles (
    user_id BIGINT PRIMARY KEY REFERENCES users(id),
    bio     TEXT
);

기본 키이자 외래 키 — "한 사용자에 한 프로필" 강제.

1:N — 한 사용자 ↔ 여러 주문

CREATE TABLE orders (
    id      BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id),
    ...
);

users 1 : orders N. 가장 흔한 관계.

N:M — 여러 사용자 ↔ 여러 태그

CREATE TABLE tags (
    id   BIGSERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

CREATE TABLE user_tags (
    user_id BIGINT REFERENCES users(id),
    tag_id  BIGINT REFERENCES tags(id),
    PRIMARY KEY (user_id, tag_id)
);

중간 테이블(join table, 두 테이블을 잇는 연결 표) 로 분해. "한 사용자에 여러 태그, 한 태그에 여러 사용자".

정규화 — 중복 제거

정규화 = "같은 사실을 한 곳에만" 박기.

❌ 비정규화 (중복)
+----+--------+----------+----------+
| id | name   | city     | country  |
+----+--------+----------+----------+
|  1 | Alice  | Seoul    | Korea    |
|  2 | Bob    | Seoul    | Korea    |    ← Korea 가 중복
|  3 | Carlos | Madrid   | Spain    |
+----+--------+----------+----------+

✅ 정규화
users                    cities
+----+--------+--------+ +--------+----------+
| id | name   |city_id | | id     | name     |
+----+--------+--------+ +--------+----------+
|  1 | Alice  |   1    | |   1    | Seoul    |
|  2 | Bob    |   1    | |   2    | Madrid   |
|  3 | Carlos |   2    | +--------+----------+
+----+--------+--------+

장점 = 데이터 일관성 + 저장 공간 절약. 단점 = JOIN 많아짐 (성능 트레이드오프).

실무 = 1NF·2NF·3NF 까지 따르는 게 표준. 너무 깊은 정규화(4NF·5NF) 는 오히려 복잡.

ACID — 관계형의 약속

Atomicity·Consistency·Isolation·Durability. 자바 백엔드 입문 43편 @Transactional 에서 다룬 트랜잭션 원칙. PG는 ACID 100% 보장.

  • A 원자성 — 모두 성공 또는 모두 실패
  • C 일관성 — 제약 조건 항상 만족
  • I 격리성 — 동시 트랜잭션 서로 영향 X (38편 MVCC, 다중 버전 동시성 제어)
  • D 영속성 — 커밋 후엔 안 사라짐 (pg_wal, PG의 변경 로그 디렉토리)

함정 5가지

(1) 콤마 분리 값을 한 셀에

tags TEXT  -- 'red,blue,green'

쿼리·검색·갱신 모두 어려움. 별도 테이블 또는 배열 타입.

(2) NULL 비교

WHERE col = NULL   -- ❌ 항상 거짓
WHERE col IS NULL  -- ✅

(3) 자연 키를 기본 키로

CREATE TABLE users (
    email TEXT PRIMARY KEY,   -- ❌ 이메일 바뀌면 외래 키 다 깨짐
    ...
);

인공 키(자동 증가·UUID)가 안전.

(4) 외래 키 없이 "코드로만" 무결성

CREATE TABLE orders (
    user_id BIGINT NOT NULL  -- ❌ FK 없음 — 잘못된 ID 박혀도 DB가 못 잡음
);

DB 수준 FK + 앱 수준 검증 둘 다.

(5) 너무 깊은 정규화

5NF 까지 분해하면 — JOIN 폭주 + 코드 복잡. 실무 = 3NF + 가끔 의도적 비정규화 (성능·캐시).

🎯 관계형 모델 핵심 5

(1) 데이터 = 테이블, 한 셀 = 단일 값. (2) 기본 키 = 행 고유 식별. (3) 외래 키 = 행 간 관계. (4) NULL ≠ NULL. (5) 1:1·1:N·N:M 세 종류 관계, N:M은 중간 테이블.

한 줄 정리 — 관계형 모델 = 테이블·행·열 + 기본 키·외래 키. 한 셀 단일 값(원자성)·NULL은 IS로 비교·인공 키 우선·FK로 무결성. 정규화는 3NF까지 표준.

시험 직전 한 번 더 — 관계형 모델 입문자가 매번 헷갈리는 것

  • 테이블 = 한 종류의 사실 묶음
  • 행(row) = 한 개체, 열(column) = 한 속성
  • 원자성 = 한 셀에 단일 값
  • 콤마 분리 값 박기 = 안티패턴
  • 기본 키 = 행 고유 식별 (테이블에 1개)
  • 인공 키 우선 — BIGSERIAL·UUID
  • 자연 키 (이메일·주민번호) 위험 — 변할 수 있음
  • 외래 키 = 다른 테이블의 기본 키 참조
  • 참조 무결성 = 존재하지 않는 ID 박기 거부
  • REFERENCES users(id) 문법
  • NULL = NULL 거짓 — IS NULL 사용
  • COUNT(col) = NULL 빼고, COUNT(*) = 모두
  • 관계 3가지 = 1:1·1:N·N:M
  • N:M = 중간 테이블 (join table)
  • 정규화 = 중복 제거, 같은 사실 한 곳에
  • 1NF = 원자값, 2NF·3NF = 부분·이행 종속 제거
  • 실무 = 3NF + 의도적 비정규화 (성능)
  • ACID = Atomicity·Consistency·Isolation·Durability
  • PG 는 ACID 100%
  • E.F.Codd = 관계형 모델 창안 (1970)
  • 50년+ 검증된 모델
  • JOIN = 정규화의 비용 (15~16편)
  • 8편 SQL 기초부터 코드로 실습

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!