본문으로 건너뛰기
데이터베이스 기초집LESSON 03

데이터베이스·스키마·테이블의 계층

난이도초급 → 중급
예상 시간35분
선수지식이전 강의

3강. 데이터베이스·스키마·테이블의 계층

1. 이번 강의에서 해결할 문제​

모든 객체를 public 스키마에 만들면 서비스 데이터, 감사 데이터, 확장 기능의 소유 관계가 흐려집니다. PostgreSQL의 계층과 연결 경계를 이해해 랭킹 서비스의 객체 위치를 정합니다.

2. 학습 목표​

3. 핵심 개념​

하나의 PostgreSQL 서버 인스턴스는 여러 데이터베이스를 가질 수 있고 연결은 한 데이터베이스를 대상으로 합니다. 데이터베이스 안의 스키마는 테이블·뷰·함수의 네임스페이스입니다. 서로 강하게 트랜잭션으로 묶이는 랭킹 데이터는 한 데이터베이스에 두고 ranking, audit처럼 책임별 스키마로 나눌 수 있습니다.

폴더에 비유하면 계층을 처음 이해하기 쉽지만 완전히 같지는 않습니다. 클러스터는 PostgreSQL 서버가 관리하는 전체 영역, 데이터베이스는 연결과 트랜잭션의 큰 경계, 스키마는 한 데이터베이스 안에서 객체 이름을 나누는 네임스페이스입니다. 테이블은 실제 행과 열을 저장하는 객체입니다.

PostgreSQL 객체 계층
PostgreSQL 클러스터
├─ game_ranking_dev 데이터베이스 ← 현재 연결 대상
│ ├─ ranking 스키마
│ │ ├─ players 테이블
│ │ └─ ranking_snapshots 테이블
│ └─ audit 스키마
│ └─ schema_events 테이블
└─ 다른 데이터베이스

한 SQL 연결은 game_ranking_dev 같은 한 데이터베이스를 선택합니다. 그 연결에서 ranking.players와 audit.schema_events는 함께 다룰 수 있지만, 다른 데이터베이스의 테이블을 일반적인 schema.table 표기로 바로 JOIN할 수는 없습니다.

용어 정리​

용어경계가 나누는 것사용할 때
클러스터서버 인스턴스가 관리하는 DB 전체서버 운영·초기화·버전 관리
데이터베이스연결, 트랜잭션, 객체의 큰 집합독립적인 서비스·환경 분리
스키마같은 DB 안의 객체 이름 공간업무 영역·권한·소유 구분
테이블행과 열로 저장되는 데이터플레이어, 경기, 감사 사건
search_path스키마를 생략했을 때 찾는 순서짧은 이름을 해석할 때

players처럼 스키마를 생략하면 PostgreSQL은 search_path 순서대로 같은 이름을 찾습니다. 개발자마다 경로가 다르면 같은 SQL이 다른 테이블을 가리킬 수 있으므로 마이그레이션과 운영 SQL에서는 ranking.players처럼 명시하는 편이 안전합니다.

4. 단계별 예시​

파일 경로: C:\dev\game-ranking-service\database\sql\03-namespaces.sql

실행 전에는 game_ranking_dev 데이터베이스에 연결했는지 확인합니다. SQL 스크립트는 새 데이터베이스를 만드는 것이 아니라 현재 연결된 데이터베이스 안에 두 스키마와 감사 테이블을 만듭니다.

database/sql/03-namespaces.sql
CREATE SCHEMA IF NOT EXISTS ranking;
CREATE SCHEMA IF NOT EXISTS audit;

CREATE TABLE IF NOT EXISTS audit.schema_events (
event_id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
event_name text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);

SELECT current_database();
SELECT current_schemas(true);
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname IN ('ranking', 'audit')
ORDER BY schemaname, tablename;

중요한 줄을 따라가기​

  1. 두 CREATE SCHEMA가 ranking, audit 이름 공간을 준비합니다. IF NOT EXISTS는 이미 있을 때 재생성 오류를 피합니다.
  2. audit.schema_events는 스키마와 테이블 이름을 점으로 연결한 완전한 이름입니다.
  3. identity 기본 키는 각 감사 사건을 유일하게 식별합니다.
  4. DEFAULT now()는 행을 넣을 때 시각을 생략하면 DB 서버가 현재 시각을 기록합니다.
  5. current_database()는 지금 어느 데이터베이스 연결에서 실행 중인지 보여 줍니다.
  6. current_schemas(true)는 현재 검색 경로에서 보이는 스키마를 보여 줍니다.
  7. pg_tables 조회는 ranking, audit에 실제로 존재하는 테이블 이름을 확인합니다.
PowerShell · 데이터베이스 생성과 확인
createdb -U postgres game_ranking_dev
psql -U postgres -d game_ranking_dev -v ON_ERROR_STOP=1 -f .\database\sql\03-namespaces.sql
psql -U postgres -d game_ranking_dev -c "\dn"

예상 확인 흐름​

  • createdb는 클러스터에 game_ranking_dev 데이터베이스를 만듭니다. 이미 있다면 오류가 날 수 있으므로 먼저 psql -l로 확인합니다.
  • psql -d game_ranking_dev는 그 데이터베이스에 연결한 뒤 SQL 파일을 실행합니다.
  • \dn에는 ranking, audit 스키마가 보여야 합니다.
  • \dt audit.*에는 audit.schema_events가 보여야 합니다.

같은 이름의 events 테이블을 두 스키마에 만들면 ranking.events와 audit.events는 서로 다른 객체입니다. 스키마를 생략한 SELECT * FROM events는 search_path에 따라 어느 것을 읽을지 달라질 수 있습니다.

5. 동작 원리​

ranking.players처럼 스키마를 명시하면 세션의 search_path가 달라도 같은 객체를 가리킵니다. 데이터베이스 경계는 연결과 트랜잭션 경계이므로 단순 분류를 위해 데이터베이스를 과도하게 나누면 JOIN과 원자적 변경이 어려워집니다.

6. 자주 하는 실수와 해결법​

7. 직접 실습​

8. 이해 점검 질문 3개​

9. 핵심 요약​

다음 강의 연결​

객체를 둘 위치를 정했으므로 이제 실제 요구사항에서 엔터티와 관계를 뽑아낼 차례입니다. 4강. 요구사항에서 엔터티와 관계 찾기에서 랭킹 서비스 문장을 스키마 후보로 바꿉니다.

MINI QUIZ

데이터베이스·스키마·테이블의 계층 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“데이터베이스·스키마·테이블의 계층”의 역할과 의존성을 판단하는 올바른 기준은 무엇인가요?
  2. 문제 2“데이터베이스·스키마·테이블의 계층”의 작업 기준으로 ‘스키마와 데이터베이스를 같은 것으로 이해’을 진단하거나 바로잡은 선택은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

3강. 데이터베이스·스키마·테이블의 계층 미완료 상태