운영 DB를 수작업으로 변경하면 안 되는 이유
운영 데이터베이스 스키마를 GUI 도구로 직접 수정했을 때 발생하는 스파게티 DB 문제와 추적 불가능성에 대해 알아봅니다.
바이브코딩으로 뚝딱뚝딱 애플리케이션을 만들다 보면 자연스럽게 데이터베이스를 다루게 됩니다. 처음에는 DBeaver나 DataGrip 같은 데이터베이스 GUI 클라이언트를 사용해 표에 컬럼을 추가하고 삭제하는 것이 아주 쉽고 직관적으로 느껴집니다. 하지만 서비스 사용자가 생기고, 코드가 복잡해지는 운영 환경에서 이런 방식은 시한폭탄과도 같습니다. 이번 시간에서는 운영 데이터베이스를 수작업으로 변경했을 때 벌어지는 치명적인 문제들을 살펴보고, 왜 체계적인 스키마(Schema) 관리가 필요한지 알아봅니다.
수작업 변경이 부르는 첫 번째 재앙: 추적 불가능성
데이터베이스 스키마를 직접 마우스로 클릭해서 수정하거나 터미널에서 즉흥적인 `ALTER TABLE` 쿼리를 실행하는 방식을 수작업 마이그레이션(Manual Migration) 이라고 부릅니다. 이 방식의 가장 큰 문제는 누가, 언제, 왜 변경했는지 기록이 남지 않는다는 점입니다.
애플리케이션 코드는 Git을 통해 변경 이력이 낱낱이 기록됩니다. 코드가 잘못되면 롤백(Rollback) 명령 한 번으로 언제든 과거의 안정적인 상태로 돌아갈 수 있습니다. 그러나 수작업으로 변경된 데이터베이스는 과거의 모습을 기억하지 못합니다.
스파게티 DB의 탄생
어느 날 신규 기능을 개발하기 위해 `users` 테이블에 `is_active`라는 컬럼을 추가했다고 가정해 봅시다. 당신은 GUI 도구에서 컬럼을 추가하고, 앱 코드를 수정해 배포했습니다. 몇 달 뒤, 다른 동료가(혹은 과거의 자신이) 이 컬럼이 왜 존재하는지, 어떤 영향을 미치는지 잊어버린 채 코드를 수정하게 됩니다.
데이터베이스에는 더 이상 쓰이지 않는 '좀비 컬럼'들이 쌓이기 시작하고, 테이블 간의 관계(Foreign Key)는 복잡하게 얽혀 도저히 손댈 수 없는 스파게티 DB 상태가 됩니다. 무엇을 지워도 안전한지 확신할 수 없기 때문에 용량 낭비와 성능 저하를 감수하면서 계속 방치하게 됩니다.
수작업 스키마 변경 시 흔히 하는 착각
오해 또는 실수
내 기억력이 좋으니까 나중에 다 기억할 수 있을 것이다.
바로잡기
몇 주만 지나도 정확한 테이블 변경 의도를 잊어버리게 됩니다.
오해 또는 실수
개발용 서버에서 바꿨으니까 운영 서버에서도 똑같이 바꾸면 된다.
바로잡기
사람의 손을 거치는 작업은 필연적으로 누락이나 실수를 유발합니다.
오해 또는 실수
급하니까 이번 한 번만 직접 수정하고 다음부터 잘 기록하자.
바로잡기
이런 예외가 쌓여서 전체 데이터베이스 정합성을 파괴합니다.
두 번째 재앙: 환경 간의 불일치
소프트웨어 개발은 보통 개발(Local) 환경, 테스트(Staging) 환경, 운영(Production) 환경이라는 3가지 이상의 서버를 거쳐 진행됩니다. 수작업으로 데이터베이스를 변경하면 이 환경 간의 스키마 구조가 어긋나는 불일치(Drift) 현상이 반드시 발생합니다.
"내 컴퓨터에서는 잘 되는데요?"
개발자는 자신의 로컬 데이터베이스에서 컬럼 이름을 `phone`에서 `phone_number`로 변경하고 신나게 코드를 짭니다. 이 코드는 정상 작동하므로 곧바로 운영 서버에 배포됩니다. 하지만 운영 서버의 데이터베이스에는 여전히 `phone` 컬럼만 존재합니다.
배포가 완료되는 순간, 운영 서버의 앱은 존재하지 않는 `phone_number` 컬럼을 찾다가 에러를 뿜어내며 서비스 전체가 다운됩니다. 이를 막기 위해서는 개발 환경에서 했던 모든 변경 작업을 메모장에 적어두었다가, 운영 서버에 배포할 때 토씨 하나 틀리지 않고 똑같이 실행해야 합니다. 이는 매우 피곤하고 오류가 발생하기 쉬운 작업입니다.
환경 불일치로 인한 대참사 시나리오
새로운 결제 시스템을 런칭하기 10분 전입니다. 프론트엔드와 백엔드 코드는 모두 성공적으로 배포되었고, 마지막으로 운영 데이터베이스에 30줄짜리 스키마 변경 쿼리를 실행해야 합니다. 하지만 너무 긴장한 나머지 복사-붙여넣기 과정에서 쿼리 한 줄을 빼먹었습니다.
그 결과, 결제 성공 여부를 저장하는 테이블이 생성되지 않았고, 런칭 후 1시간 동안 발생한 수천 건의 결제 데이터가 그대로 증발해 버렸습니다. 환경 간의 데이터베이스 상태가 코드로 보장되지 않았기 때문에 발생한 비극입니다.
세 번째 재앙: 동시성 충돌과 협업의 파괴
혼자서 바이브코딩을 할 때는 그나마 괜찮을 수 있습니다. 하지만 두 명 이상의 개발자나 에이전트가 동시에 같은 데이터베이스를 수정하려고 하면 끔찍한 충돌이 발생합니다.
덮어쓰기 문제
A 개발자가 `posts` 테이블에 `view_count` 컬럼을 추가하고 앱 코드를 작성하는 동안, B 개발자는 같은 테이블에 `like_count` 컬럼을 추가했습니다. 두 사람이 각자의 데이터베이스에서 코드를 짤 때는 문제가 없었습니다.
하지만 운영 서버에 배포할 때, 누구의 스키마 변경 사항을 먼저 반영해야 할까요? 만약 A의 변경만 반영되고 B의 변경은 누락된다면, B가 만든 기능은 즉각 장애를 일으킵니다. 이를 해결하려면 개발자들끼리 끊임없이 소통하며 "내가 테이블 구조를 바꿨으니 너도 맞춰라"라고 동기화해야 하는데, 이는 심각한 생산성 저하를 불러옵니다.
수작업 방식 vs 시스템 기반 마이그레이션
| 비교 항목 | 수작업 변경 (GUI / 쿼리 직접 실행) | 마이그레이션 자동화 도구 |
|---|---|---|
| 변경 이력 추적 | 불가능 (누가 무엇을 바꿨는지 알 수 없음) | Git과 동일하게 모든 이력 확인 가능 |
| 환경 일관성 | 개발/운영 환경이 쉽게 어긋남 | 모든 환경이 동일한 구조를 유지 |
| 롤백 (되돌리기) | 데이터가 유실되거나 구조 복원 어려움 | 다운(Down) 스크립트를 통해 안전하게 복원 |
| 팀 협업 | 충돌 빈번, 변경 사항을 구두로 공유해야 함 | 코드 병합 과정을 통해 충돌 방지 및 자동화 |
요약하자면: 데이터베이스 변경도 '코드'입니다
데이터베이스 스키마는 한 번 만들어두고 끝나는 정적인 구조물이 아닙니다. 애플리케이션의 발전과 함께 지속적으로 진화하는 살아있는 유기체와 같습니다.
따라서 데이터베이스 구조를 변경하는 모든 행위는 애플리케이션의 소스 코드와 똑같은 수준의 엄격함으로 관리되어야 합니다. 그래야만 예측 가능하고, 안전하며, 두려움 없이 코드를 배포할 수 있습니다. 수작업의 유혹에서 벗어나는 것이 무중단 데이터베이스 운영의 첫걸음입니다.
개념 퀴즈
퀴즈 답을 맞춰야 학습 완료가 됩니다.운영 데이터베이스를 수작업으로 변경(GUI 도구 사용 등)했을 때 발생하는 문제점으로 적절하지 않은 것은 무엇인가요?
3줄 요약
- 1수작업으로 DB를 변경하면 언제, 왜 변경했는지 알 수 없어 점차 관리 불가능한 '스파게티 DB'가 됩니다.
- 2로컬 개발 환경과 실제 운영 환경의 DB 구조가 어긋나는 '불일치' 현상으로 인해 배포 시 치명적인 장애가 발생합니다.
- 3데이터베이스 스키마 역시 앱 소스코드와 동일하게 다뤄야 하며, 시스템 기반의 자동화된 마이그레이션이 필수적입니다.