백엔드 데이터 인프라 21편 — DDL 개요 데이터 정의 언어 전체 그림

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

백엔드 데이터 인프라 21편. DDL의 큰 그림 — 테이블·스키마·시퀀스·인덱스·뷰·도메인·트리거 PG 객체 종류와 명명 패턴 풀어쓴 학습 노트.

📚 백엔드 데이터 인프라 · 21편 — DDL 개요 데이터 정의 언어 전체 그림

이 글은 백엔드 데이터 인프라 시리즈 70편 중 21편이에요. 9편 CREATE TABLE 에서 "테이블 만들기" 를 다뤘다면, 이번 21편은 DDL의 큰 그림 — PG가 다루는 객체 전체 + 분류 + 명명 패턴.

DDL이 헷갈리는 이유

CREATE·ALTER·DROP 만 안다고 끝이 아니에요. PG는 "테이블" 외에도 — 시퀀스·인덱스·뷰·머티리얼라이즈드 뷰·도메인·타입·함수·트리거·확장·외래 데이터 래퍼 등 10가지 이상 객체 종류. 각각 별도 DDL.

이 글은 "어떤 객체가 있고, 각각 언제 쓰나" 의 지도. 22편부터 각 객체 깊이.

PG 객체 — 10대 종류

객체 의미 자주 쓰임
TABLE 데이터 저장 단위 ★★★ 거의 모든 곳
SCHEMA 객체 그룹·네임스페이스 ★★★ 큰 시스템
INDEX 조회 가속 ★★★ 운영 필수
SEQUENCE 자동 증가 정수 생성기 ★★★ BIGSERIAL 내부
VIEW 저장된 쿼리 ★★ 추상화
MATERIALIZED VIEW 캐시된 뷰 ★★ 대시보드
DOMAIN 사용자 정의 타입 + 제약 ★ 가끔
TYPE (Composite·Enum) 사용자 정의 타입 ★ 가끔
FUNCTION·PROCEDURE 사용자 정의 함수 ★★ 트리거·복잡 로직
TRIGGER 이벤트 자동 실행 ★★ 감사·자동 갱신
EXTENSION PG 확장 (postgis·pg_cron 등) ★★ 특수 기능
FOREIGN TABLE 외부 데이터 매핑 ★ 가끔

SCHEMA — 객체 그룹

3편 아키텍처 의 4단계 계층(Cluster→Database→Schema→Table) 중 3단계.

CREATE SCHEMA app;
CREATE SCHEMA audit;
CREATE SCHEMA reporting;

CREATE TABLE app.users (...);
CREATE TABLE audit.user_changes (...);

큰 시스템 = 스키마로 분리. 기본 = public 스키마.

search_path

SET search_path TO app, public;
SELECT * FROM users;     -- 자동으로 app.users 찾음

스키마 명시 안 하면 — search_path 순서대로 검색.

SEQUENCE — 자동 증가 정수

CREATE SEQUENCE user_id_seq START WITH 1 INCREMENT BY 1;

INSERT INTO users (id, name) VALUES (nextval('user_id_seq'), 'Alice');

BIGSERIAL 도 내부적으로 시퀀스.

CREATE TABLE users (id BIGSERIAL PRIMARY KEY);
-- 자동으로 users_id_seq 시퀀스 생성
-- DEFAULT nextval('users_id_seq') 박힘

IDENTITY — 표준 SQL 스타일

CREATE TABLE users (
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name TEXT
);

PG 10+ 표준. BIGSERIAL과 차이: - BIGSERIAL = 시퀀스 별도 노출 (직접 접근 가능) - IDENTITY = 시퀀스 묵음 (DEFAULT 같은 형태)

신규 코드 = IDENTITY 권장 (SQL 표준 호환).

INDEX — 조회 가속

CREATE INDEX idx_users_email ON users(email);
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);
CREATE INDEX idx_orders_created ON orders(created_at DESC);

PG 인덱스 6종 — 34~36편에서 깊이.

VIEW·MATERIALIZED VIEW

16편 VIEW 에서 다룬 둘. 정의·캐시·갱신.

DOMAIN — 사용자 정의 타입

CREATE DOMAIN email_address AS TEXT
    CHECK (VALUE ~ '^[^@]+@[^@]+\.[^@]+$');

CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    email email_address
);

도메인 = "TEXT + 이메일 형식 검증" 묶음 타입. 여러 테이블에서 재사용.

TYPE — Composite·Enum

Composite Type

CREATE TYPE address AS (
    zip_code TEXT,
    city     TEXT,
    street   TEXT
);

CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    home_addr address,
    work_addr address
);

Enum

CREATE TYPE order_status AS ENUM ('PENDING', 'PAID', 'SHIPPED', 'DELIVERED', 'CANCELED');

CREATE TABLE orders (
    id BIGSERIAL PRIMARY KEY,
    status order_status NOT NULL DEFAULT 'PENDING'
);

CHECK 제약 + TEXT 의 대안. ENUM 단점 = "새 값 추가 시 ALTER TYPE" 필요.

FUNCTION·PROCEDURE

CREATE OR REPLACE FUNCTION fullname(first TEXT, last TEXT)
RETURNS TEXT AS $$
    SELECT first || ' ' || last;
$$ LANGUAGE sql;

SELECT fullname('Alice', 'Kim');    -- 'Alice Kim'

복잡한 비즈니스 로직을 PG 안에. PL/pgSQL·SQL·Python·JavaScript 등 다양한 언어.

-- PL/pgSQL 함수
CREATE FUNCTION calculate_age(birth DATE)
RETURNS INTEGER AS $$
DECLARE
    age INTEGER;
BEGIN
    age := EXTRACT(YEAR FROM AGE(birth));
    RETURN age;
END;
$$ LANGUAGE plpgsql;

PROCEDURE = PG 11+ 추가. 트랜잭션 안 commit 가능 (FUNCTION은 불가).

TRIGGER — 이벤트 자동 실행

CREATE FUNCTION update_modified()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER users_modified
BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION update_modified();

updated_at 자동 갱신·감사 로그·캐시 무효화 등.

타이밍: - BEFORE — 변경 전 - AFTER — 변경 후 - INSTEAD OF — 뷰의 INSERT·UPDATE 가로채기

EXTENSION — PG 확장

PG는 확장 기능 풍부.

CREATE EXTENSION IF NOT EXISTS pgcrypto;       -- 암호화 함수
CREATE EXTENSION IF NOT EXISTS uuid-ossp;      -- UUID 생성
CREATE EXTENSION IF NOT EXISTS pg_trgm;        -- 유사 문자열 검색
CREATE EXTENSION IF NOT EXISTS postgis;        -- 지리 정보
CREATE EXTENSION IF NOT EXISTS pg_cron;        -- cron 스케줄러
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;  -- 쿼리 통계

운영 PG 거의 다 이 중 일부 활용.

FOREIGN TABLE — 외부 데이터

CREATE EXTENSION postgres_fdw;

CREATE SERVER otherdb FOREIGN DATA WRAPPER postgres_fdw
    OPTIONS (host '...', dbname 'other');

CREATE FOREIGN TABLE remote_users (id BIGINT, name TEXT)
    SERVER otherdb OPTIONS (schema_name 'public', table_name 'users');

SELECT * FROM remote_users;    -- 다른 PG의 테이블처럼

다른 DB·CSV·MongoDB 등을 "PG 테이블처럼" 조회. 데이터 마이그레이션·분산 쿼리에 강력.

명명 패턴 — 한국 회사 표준

객체 패턴
테이블 snake_case 복수 users·order_items
컬럼 snake_case user_id·created_at
인덱스 idx_<테이블>_<컬럼> idx_users_email
유니크 인덱스 uniq_<테이블>_<컬럼> uniq_users_email
외래 키 fk_<테이블>_<참조> fk_orders_user
시퀀스 <테이블>_<컬럼>_seq users_id_seq (자동)
트리거 tr_<테이블>_<이벤트> tr_users_updated
함수 snake_case calculate_age
vw_* 또는 그대로 active_users·vw_user_stats

DDL 트랜잭션 — PG 강점

BEGIN;
ALTER TABLE users ADD COLUMN status TEXT;
ALTER TABLE users ADD COLUMN level INTEGER;
CREATE INDEX idx_users_status ON users(status);
COMMIT;    -- 또는 ROLLBACK

PG는 DDL이 트랜잭션 안에서 동작. MySQL은 일부 DDL이 암묵 커밋. 이게 PG의 큰 운영 장점.

함정 5가지

(1) BIGSERIAL vs IDENTITY 혼용

같은 시스템 안에 둘 섞이면 — 일관성 깨짐. 신규 = IDENTITY 통일.

(2) ENUM 변경 어려움

ENUM 새 값 추가 = ALTER TYPE ... ADD VALUE. 값 삭제는 매우 어려움. "안정적으로 정해진 상태" 만 ENUM.

(3) DOMAIN 너무 많음

도메인 = 재사용 좋지만 — 너무 많이 만들면 관리 부담. 정말 "여러 테이블에 반복" 일 때만.

(4) FUNCTION 비즈니스 로직 박기

DB에 비즈니스 로직 박으면 — 버전 관리·테스트 어려움. 핵심 로직 = 앱 코드, DB는 "무결성·자동화" 만.

(5) EXTENSION 운영에 임의 박기

운영 PG에 확장 추가는 — DBA·인프라 팀 협업. 클러스터 재시작 필요한 경우도.

🎯 DDL 객체 우선순위

★★★ 거의 매일 = TABLE·INDEX·SCHEMA·SEQUENCE. ★★ 자주 = VIEW·TRIGGER·EXTENSION. ★ 가끔 = DOMAIN·TYPE·FUNCTION·FOREIGN TABLE. 입문자는 ★★★ 4가지부터.

한 줄 정리 — PG DDL 객체 10대 종류. TABLE·SCHEMA·INDEX·SEQUENCE 4가지가 운영 핵심. PG는 DDL이 트랜잭션 안 동작 — 운영 강점. 확장(EXTENSION)으로 강력한 추가 기능. JPA가 DDL 자동 생성하지만 — 운영 깊이 이해 필요.

시험 직전 한 번 더 — DDL 입문자가 매번 헷갈리는 것

  • DDL 객체 10대 = TABLE·SCHEMA·INDEX·SEQUENCE·VIEW·MATERIALIZED VIEW·DOMAIN·TYPE·FUNCTION·TRIGGER·EXTENSION·FOREIGN TABLE
  • SCHEMA = 네임스페이스 (4단계 계층 3단계)
  • search_path = 스키마 검색 순서
  • SEQUENCE = 자동 증가 정수 생성기
  • IDENTITY = SQL 표준 시퀀스 (PG 10+)
  • BIGSERIAL = PG 옛 스타일 (시퀀스 노출)
  • IDENTITY 권장 = 신규 표준
  • DOMAIN = TEXT + CHECK 묶음 타입
  • ENUM = 고정 값 집합
  • ENUM 값 추가 = ALTER TYPE ADD VALUE
  • ENUM 값 삭제 = 어려움
  • Composite Type = 컬럼 묶음
  • FUNCTION = 사용자 정의 함수 (sql·plpgsql 등)
  • PROCEDURE = PG 11+ 트랜잭션 가능
  • TRIGGER = BEFORE·AFTER·INSTEAD OF
  • updated_at 자동 갱신 = TRIGGER 표준
  • EXTENSION = pgcrypto·uuid-ossp·pg_trgm·postgis·pg_cron 등
  • FOREIGN TABLE = 외부 DB·CSV 매핑
  • PG DDL = 트랜잭션 안 (MySQL과 차이)
  • 명명 = snake_case lowercase
  • 인덱스 명명 = idx_<테이블>_<컬럼>
  • FK 명명 = fk_<테이블>_<참조>
  • 비즈니스 로직 = 앱 코드 (DB는 무결성만)
  • ★★★ 4가지 = TABLE·SCHEMA·INDEX·SEQUENCE

시리즈 다른 편

시리즈 다음 글

다음 글(22편)에서는 CREATE TABLE 깊이 — PARTITION·INHERITS·UNLOGGED·TEMPORARY 고급 옵션.

공식 문서: PostgreSQL 18 — Data Definition에서 더 자세한 사양을 확인할 수 있어요.

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

답글 남기기

error: Content is protected !!