PostgreSQL 교재 · 3편 / 24편

데이터베이스·스키마·테이블 만들기

DB → 스키마 → 테이블 순서로 만들고, 명명 규칙·DROP 의 주의·권한 한 줄까지.

입문읽는 시간 7분2026-05-16
PostgreSQL 의 DB·스키마·테이블 계층 구조가 그림으로 보이는 일러스트

PostgreSQL 안에서 데이터는 계층 구조로 정리됩니다. 가장 바깥에 데이터베이스(database), 그 안에 스키마(schema), 그 안에 테이블(table)·뷰·함수가 있습니다. 3편에서는 이 세 계층을 직접 만들고, 적절한 이름을 짓고, 안전하게 지우는 법까지 정리합니다.

계층 구조 — DB ⊃ 스키마 ⊃ 테이블

계층 한 줄. 클러스터(서버 한 대) → 데이터베이스 N 개스키마 N 개(기본 public) → 테이블·뷰·함수 N 개.

실무에서는 서비스 하나 = DB 하나가 가장 흔합니다. 한 DB 안의 모듈(인증·결제·로그 등) 을 스키마로 나누는 경우도 많습니다.

CREATE DATABASE

postgres=# CREATE DATABASE myshop
             OWNER junai_app
             ENCODING 'UTF8'
             LC_COLLATE 'ko_KR.UTF-8'
             LC_CTYPE   'ko_KR.UTF-8'
             TEMPLATE template0;
CREATE DATABASE

-- 접속
postgres=# \c myshop
You are now connected to database "myshop"
myshop=#

한국어 정렬·대소문자 처리에 LC_COLLATE/LC_CTYPE 가 영향을 줍니다. 한국어 환경이라면 ko_KR.UTF-8 을 권장. TEMPLATE template0 은 "빈 베이스에서 시작" 이라는 뜻으로, locale 충돌을 피하는 안전한 기본값입니다.

CREATE SCHEMA — 모듈 분리

myshop=# CREATE SCHEMA shop;        -- 상품·주문 모듈
myshop=# CREATE SCHEMA auth;        -- 회원·세션 모듈
myshop=# CREATE SCHEMA log;         -- 로그 보관

-- 스키마 안에 테이블
myshop=# CREATE TABLE shop.products (...);
myshop=# CREATE TABLE auth.users    (...);

-- 매번 shop. 을 안 적으려면 search_path 설정
myshop=# SET search_path TO shop, public;
myshop=# CREATE TABLE orders (...);   -- shop.orders 가 됨

스키마는 "네임스페이스" 라고 생각하면 됩니다. shop.usersauth.users 가 같은 DB 안에서 충돌 없이 공존할 수 있게요. 작은 서비스는 public 하나만 써도 충분합니다.

CREATE TABLE — 첫 테이블

CREATE TABLE shop.products (
  id          BIGSERIAL PRIMARY KEY,
  name        TEXT       NOT NULL,
  slug        TEXT       NOT NULL UNIQUE,
  price       NUMERIC(10,2) NOT NULL CHECK (price >= 0),
  stock       INTEGER    NOT NULL DEFAULT 0,
  attributes  JSONB      NOT NULL DEFAULT '{}'::jsonb,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at  TIMESTAMPTZ
);

-- 빠른 조회용 인덱스
CREATE INDEX ix_products_created ON shop.products (created_at DESC);
CREATE INDEX ix_products_attrs   ON shop.products USING GIN (attributes);

이 한 정의 안에 4편(자료형)·5편(CRUD)·16편(인덱스) 의 미리보기가 다 들어 있습니다.

  • BIGSERIAL — 자동 증가 정수 PK (1, 2, 3...)
  • NOT NULL — 비어 있을 수 없음
  • UNIQUE — 같은 값 중복 금지
  • CHECK (price >= 0) — 값 제약
  • DEFAULT — 입력 안 하면 기본값
  • JSONB — 구조 자유 데이터(12편 에서 자세히)
  • TIMESTAMPTZ — 시간대 인식 시각

명명 규칙 — 미래의 나를 위해

이름은 한 번 정하면 바꾸기 어렵습니다. 처음부터 일관되게.

대상관례예시
테이블snake_case · 복수형users, order_items
컬럼snake_case · 짧고 명확created_at, total_price
PKid 또는 {table}_idid, user_id
FK{참조테이블}_idproducts.user_id → users.id
인덱스ix_{table}_{cols}ix_products_created
유니크uq_{table}_{cols}uq_users_email
제약ck_{table}_{rule}ck_products_price_pos

예약어 충돌 주의. user, order, group, type 등은 SQL 예약어입니다. 컬럼/테이블 이름으로 쓰면 매번 큰따옴표로 감싸야 해서 짜증납니다. users(복수), account, group_name 처럼 살짝 다르게 짓는 게 정신 건강에 좋습니다.

DROP — 안전하게 지우기

-- 테이블
DROP TABLE shop.products;                   -- 없으면 에러
DROP TABLE IF EXISTS shop.products;         -- 없어도 통과 (안전)

-- 참조하는 외래키도 같이
DROP TABLE shop.products CASCADE;           -- ⚠️ 다른 곳도 같이 날아감

-- 스키마 통째
DROP SCHEMA shop CASCADE;                   -- ⚠️ 안의 모든 테이블 삭제

-- 데이터베이스 (현재 접속 중인 DB 는 못 지움)
\c postgres
DROP DATABASE myshop;

운영 DB 에서 절대 금지. DROP ... CASCADEDROP DATABASE 는 되돌릴 수 없습니다. 운영 환경에서는 먼저 백업(20편), 트랜잭션 안에서 시험(14편), 권한 분리(따로 deploy 계정) 가 필수. 학습용 docker 컨테이너에서는 자유롭게 실험해도 OK — 컨테이너 지우면 끝.

4편 — 데이터 타입 7묶음

int·numeric·text·varchar·boolean·uuid·jsonb·timestamptz·array — 어떤 데이터에 무엇을 골라야 후회가 없는가.

📚 PostgreSQL 배우기 교재
이전: 2편 psql · 현재: 3편 (입문) · 다음 → 4편 자료형 · 진행: 3/24

© 2026 주나이테크(주) @JUNAITECH