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

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

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

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

이 글은 백엔드 데이터 인프라 시리즈 70편 중 21편이에요. 9편 CREATE TABLE 에서 "테이블 만들기" 를 다뤘다면, 이번 21편은 DDL(Data Definition Language, 객체 정의 SQL)의 큰 그림을 그려요. 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 같은 형태)

신규 코드라면 SQL 표준 호환이 되는 IDENTITY를 권장해요.

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(PG의 절차형 언어)·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(Java Persistence API, 자바 ORM 표준)가 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

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

이전 글:

다음 글:

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

답글 남기기

error: Content is protected !!