데이터베이스 정규화/비정규화 패턴 라이브러리. 1NF~BCNF 판별 기준, 함수 종속성 분석, 정규화 단계별 변환 절차, 전략적 비정규화 패턴, 공통 도메인 ERD 템플릿을 제공하는 data-modeler 확장 스킬. '정규화', '비정규화', 'ERD 패턴', '함수 종속성', '테이블 분리', '관계 설계' 등 데이터 모델링 시 사용한다. 단, DDL 생성이나 쿼리 최적화는 이 스킬의 범위가 아니다.
Scanned 5/29/2026
Install via CLI
openskills install revfactory/harness-100---
name: normalization-patterns
description: "데이터베이스 정규화/비정규화 패턴 라이브러리. 1NF~BCNF 판별 기준, 함수 종속성 분석, 정규화 단계별 변환 절차, 전략적 비정규화 패턴, 공통 도메인 ERD 템플릿을 제공하는 data-modeler 확장 스킬. '정규화', '비정규화', 'ERD 패턴', '함수 종속성', '테이블 분리', '관계 설계' 등 데이터 모델링 시 사용한다. 단, DDL 생성이나 쿼리 최적화는 이 스킬의 범위가 아니다."
---
# Normalization Patterns — 정규화/비정규화 패턴 라이브러리
data-modeler 에이전트가 데이터 모델링 시 활용하는 정규화 규칙, 비정규화 전략, 도메인별 ERD 패턴.
## 대상 에이전트
`data-modeler` — 이 스킬의 정규화 규칙과 ERD 패턴을 데이터 모델 설계에 직접 적용한다.
## 정규화 단계 판별 & 변환
### 1NF (제1정규형)
**규칙**: 모든 컬럼은 원자값(atomic value)이어야 한다.
| 위반 패턴 | 문제 | 해결 |
|----------|------|------|
| 다중값 컬럼 | `tags = "java,python,go"` | 별도 테이블 분리 (M:N) |
| 반복 그룹 | `phone1, phone2, phone3` | 별도 테이블 분리 (1:N) |
| 복합값 | `address = "서울시 강남구 역삼동"` | 시/구/동 컬럼 분리 |
### 2NF (제2정규형)
**전제**: 1NF 만족
**규칙**: 부분 함수 종속성 제거 — 복합 기본키의 일부에만 종속되는 컬럼 분리.
| 위반 예 | 종속 관계 | 해결 |
|--------|----------|------|
| `주문상세(주문ID, 상품ID, 상품명, 수량)` | 상품명 → 상품ID에만 종속 | 상품 테이블 분리 |
### 3NF (제3정규형)
**전제**: 2NF 만족
**규칙**: 이행적 함수 종속성 제거 — 기본키가 아닌 컬럼이 다른 비키 컬럼을 결정하면 안 됨.
| 위반 예 | 종속 관계 | 해결 |
|--------|----------|------|
| `직원(ID, 부서ID, 부서명, 부서장)` | 부서명, 부서장 → 부서ID 종속 (이행적) | 부서 테이블 분리 |
### BCNF (보이스-코드 정규형)
**규칙**: 모든 결정자(determinant)가 후보키여야 한다.
| 위반 예 | 문제 | 해결 |
|--------|------|------|
| `수강(학생, 과목, 교수)` 여기서 교수→과목 | 교수가 결정자이지만 후보키 아님 | 교수-과목 테이블 분리 |
## 정규화 결정 흐름도
```
데이터 분석
├─ 원자값 위반? → 1NF 변환
├─ 복합키 & 부분 종속? → 2NF 변환
├─ 이행적 종속? → 3NF 변환
├─ 비후보키 결정자? → BCNF 변환
└─ 성능 요구사항 → 전략적 비정규화 검토
```
## 전략적 비정규화 패턴
### 언제 비정규화하는가?
- 읽기 >> 쓰기 비율이 높을 때
- JOIN이 5개 이상 필요한 빈번한 쿼리
- 실시간 집계/통계가 필요할 때
- 대시보드/리포트 전용 데이터
### 비정규화 패턴 카탈로그
| 패턴 | 설명 | 적합 상황 | 트레이드오프 |
|------|------|----------|-----------|
| **파생 컬럼** | 계산값 저장 (`total_price`) | 빈번한 합계 조회 | 갱신 시 동기화 필요 |
| **중복 컬럼** | FK 대상의 자주 쓰는 컬럼 복사 | JOIN 회피 | 데이터 불일치 위험 |
| **사전 조인 테이블** | 조인 결과를 물리 테이블로 | 리포트/대시보드 | 저장 공간, 갱신 복잡 |
| **히스토리 스냅샷** | 시점 데이터 보존 (`order_address`) | 주문 시점 주소 보관 | 저장 공간 |
| **카운터 컬럼** | `likes_count`, `comments_count` | 실시간 카운트 표시 | 동시성 처리 |
| **JSON/JSONB** | 구조화되지 않은 확장 데이터 | 설정, 메타데이터 | 인덱싱 제한 |
## 공통 도메인 ERD 패턴
### 이커머스
```
users ──1:N──> orders ──1:N──> order_items
│ │
└──1:N──> addresses products
└──1:N──> reviews ──N:1──────┘
│
products ──N:M──> categories (via product_categories)
products ──1:N──> product_images
products ──1:N──> product_variants
```
핵심 테이블:
- `users` (id, email, name, password_hash, created_at)
- `products` (id, name, description, base_price, status)
- `orders` (id, user_id, status, total, shipping_address_snapshot)
- `order_items` (id, order_id, product_id, variant_id, quantity, unit_price)
### SaaS 멀티테넌트
```
tenants ──1:N──> users ──N:M──> roles (via user_roles)
│ │
└──1:N──> subscriptions permissions ──N:M──> roles
└──1:N──> [도메인 테이블] (tenant_id FK)
```
핵심: 모든 비즈니스 테이블에 `tenant_id` 포함, RLS(Row Level Security) 적용
### 소셜 네트워크
```
users ──N:M──> users (via follows: follower_id, following_id)
│
└──1:N──> posts ──1:N──> comments
│ └──N:M──> tags (via post_tags)
│ └──1:N──> likes (user_id + post_id UNIQUE)
└──1:N──> messages (sender_id, receiver_id)
```
### CMS/블로그
```
users ──1:N──> posts ──N:M──> tags (via post_tags)
│
└──1:N──> comments (self-referencing: parent_id)
└──1:N──> media
└──1:1──> post_meta (SEO, OG 등)
```
## 관계 패턴
### 1:1 관계
- 큰 테이블 분할 (자주 쓰는 컬럼 vs 가끔 쓰는 컬럼)
- 선택적 확장 (`user` + `user_profile`)
- 구현: FK + UNIQUE 제약
### 1:N 관계
- 가장 흔한 관계
- 자기참조: 카테고리 트리, 댓글 스레드 (`parent_id`)
- 구현: 자식 테이블에 FK
### M:N 관계
- 중간 테이블(junction table) 필수
- 중간 테이블에 추가 속성 가능 (`created_at`, `role`, `quantity`)
- 네이밍: `{table1}_{table2}` 또는 의미 있는 이름 (`enrollments`)
## 공통 컬럼 패턴
### 기본 타임스탬프
모든 테이블에 포함:
- `id` — UUID 또는 BIGINT AUTO_INCREMENT
- `created_at` — TIMESTAMPTZ DEFAULT NOW()
- `updated_at` — TIMESTAMPTZ, 트리거로 자동 갱신
### Soft Delete
- `deleted_at` — TIMESTAMPTZ NULL (NULL이면 미삭제)
- 모든 쿼리에 `WHERE deleted_at IS NULL` 조건
- 복원 가능, 감사 로그 역할
### 상태 관리
- `status` — ENUM 또는 VARCHAR
- 상태 전이 규칙 문서화 필수 (어떤 상태에서 어떤 상태로?)
- 이력이 필요하면 별도 `status_history` 테이블
### 다국어
- 전략 1: 컬럼 확장 (`name_ko`, `name_en`, `name_ja`)
- 전략 2: 번역 테이블 (`product_translations`: product_id, locale, name, description)
- 전략 2 권장 (언어 추가 시 스키마 변경 불필요)
No comments yet. Be the first to comment!