모든 스키마 변경을 파일과 버전으로 관리하기
데이터베이스 스키마 변경 사항을 소스 코드처럼 파일(.sql)로 만들고 버전 번호를 매겨 관리하는 원리를 배웁니다.
이전 에피소드에서 데이터베이스를 수작업으로 변경하는 것이 얼마나 위험한지 알아보았습니다. 그렇다면 안전한 대안은 무엇일까요? 바로 데이터베이스 스키마의 변경 사항을 일반 애플리케이션의 소스 코드처럼 다루는 것입니다. 이번 회차에서는 변경 사항을 파일로 저장하고, 버전 번호를 매겨 순차적으로 관리하는 '마이그레이션(Migration) 파일 시스템'의 핵심 원리와 작동 방식을 낱낱이 파헤쳐 봅니다.
마이그레이션 파일이란 무엇인가?
소프트웨어 엔지니어링에서 마이그레이션(Migration) 은 데이터베이스 스키마를 한 상태에서 다음 상태로 변환하는 과정을 의미합니다. 이 변환 과정을 담은 명령어들의 모음을 마이그레이션 파일이라고 부릅니다.
마이그레이션 파일은 마법 같은 기술이 아닙니다. 본질적으로는 `.sql` 확장자를 가진 아주 평범한 텍스트 파일에 불과합니다. 하지만 이 텍스트 파일들을 다루는 '규칙'이 마이그레이션 시스템의 핵심입니다.
파일 기반 관리의 원칙
개발자가 데이터베이스에 새로운 테이블을 추가하고 싶을 때, GUI 도구에서 바로 `CREATE TABLE`을 실행하는 대신 다음과 같은 절차를 따릅니다.
- 새로운 빈 텍스트 파일을 생성합니다.
- 그 파일 안에 `CREATE TABLE` SQL 쿼리를 작성합니다.
- 파일 이름을 규칙에 맞게 짓고 프로젝트 소스코드 폴더(Git)에 저장합니다.
- 마이그레이션 실행 도구가 이 파일을 읽어서 데이터베이스에 쿼리를 실행합니다.
간단한 마이그레이션 파일 예시
`users` 테이블을 생성하기 위해 작성한 파일 `create_users_table.sql`의 내부 모습입니다.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);이렇게 하면 "테이블을 생성했다"는 행위 자체가 코드로 박제되어 영구적으로 남게 됩니다. 다른 팀원이 코드를 내려받으면 어떤 쿼리가 실행되어야 하는지 명확히 알 수 있습니다.
버전 번호의 마법: 순서 보장하기
파일을 생성하는 것만으로는 부족합니다. 데이터베이스는 순서에 매우 민감합니다. 예를 들어 `posts` 테이블을 생성하기도 전에 `posts` 테이블에 컬럼을 추가하는 파일이 먼저 실행되면 당연히 에러가 발생합니다.
따라서 모든 마이그레이션 파일에는 반드시 엄격한 실행 순서를 보장하는 고유한 버전(Version) 번호가 부여되어야 합니다.
마이그레이션 파일 이름의 일반적인 구조
- 버전 번호 (Prefix)
- 실행 순서를 결정하는 숫자. 타임스탬프(YYYYMMDDHHMMSS)나 순차적인 정수(0001, 0002)를 사용합니다.
- 구분자
- 버전 번호와 설명을 분리하기 위해 보통 언더스코어(_)를 사용합니다.
- 설명 (Description)
- 이 파일이 어떤 변경을 수행하는지 사람이 읽을 수 있게 작성한 짧은 요약입니다.
- 확장자
- 대부분 `.sql`을 사용합니다.
예를 들면 이런 식입니다.
- `001_create_users.sql`
- `002_add_phone_number_to_users.sql`
- `003_create_orders.sql`
마이그레이션 실행 도구(Migrator)는 폴더 안에 있는 파일들을 스캔한 뒤, 이 숫자 순서대로 정렬하여 차례대로 데이터베이스에 밀어 넣습니다.
스키마 기록부: schema_migrations 테이블
여기서 중요한 질문이 생깁니다. "데이터베이스는 자신이 몇 번 마이그레이션 파일까지 실행했는지 어떻게 알까요?"
만약 마이그레이션 도구가 매번 `001_create_users.sql`부터 다시 실행한다면, 이미 존재하는 테이블을 또 만들려고 시도하다가 치명적인 충돌이 발생할 것입니다.
이를 해결하기 위해 마이그레이션 시스템은 데이터베이스 내부에 아주 작고 특별한 테이블 하나를 몰래 만듭니다. 주로 `schema_migrations` 또는 `migrations`라는 이름을 가집니다. 이 테이블의 역할은 단순명료합니다. "지금까지 성공적으로 실행한 버전 번호들을 기록해 두는 장부" 역할을 하는 것입니다.
마이그레이션 도구의 실행 로직
- 1프로젝트 폴더 내의 마이그레이션 파일 목록(001, 002, 003)을 읽어 들인다.
- 2데이터베이스의 'schema_migrations' 장부 테이블을 조회하여 이미 실행된 버전을 확인한다.
- 3장부에 없는 새로운 버전 번호(예: 003)의 파일만 골라낸다.
- 4해당 파일의 SQL을 데이터베이스에 실행한다.
- 5실행이 성공하면 장부(schema_migrations)에 '003'이라는 번호를 추가로 기록한다.
환경의 독립성 보장
이 영리한 구조 덕분에, 개발 환경과 운영 환경의 불일치 문제가 완벽하게 해결됩니다.
- 내 로컬 컴퓨터의 DB에는 `001`, `002`까지 기록되어 있다면, 도구를 실행했을 때 `003`만 실행됩니다.
- 막 배포된 운영 서버의 DB에 `001`까지만 기록되어 있다면, 도구가 알아서 `002`와 `003`을 순차적으로 실행해 줍니다.
어떤 환경이든 상관없이, 단순히 코드(마이그레이션 파일)를 최신으로 다운로드받고 마이그레이션 명령어 한 줄만 치면 모든 스키마가 완벽하게 동일한 상태로 동기화되는 것입니다.
파일과 버전 관리의 효과
변경 사항을 파일(.sql)로 남김
→Git을 통해 누가 언제 왜 데이터베이스를 변경했는지 완벽히 추적 가능
파일 이름에 순차적인 버전 번호 부여
→DB 스키마가 꼬이지 않고 의도된 순서대로 정확히 구축됨
DB 내부에 schema_migrations 장부 사용
→여러 환경(개발, 운영)에서 중복 실행 없이 현재 상태에 맞춰 자동 동기화됨
개념 퀴즈
퀴즈 답을 맞춰야 학습 완료가 됩니다.마이그레이션 시스템이 파일의 중복 실행을 막고 현재 데이터베이스 상태를 파악하기 위해 사용하는 일반적인 핵심 원리는 무엇인가요?
3줄 요약
- 1마이그레이션은 DB 변경 사항을 평범한 텍스트 파일(.sql)에 작성하여 코드로 관리하는 방식입니다.
- 2각 파일은 접두어에 고유한 번호(예: 001, 타임스탬프)를 가져 엄격한 실행 순서를 보장해야 합니다.
- 3데이터베이스 내부의 상태 기록 테이블(schema_migrations)을 통해 중복 실행을 막고 모든 환경을 안전하게 동기화합니다.