디스크 공간이 부족할 때: MySQL 데이터베이스 클렌징에 도전하는 교훈
Source: Dev.to
디스크 공간이 부족할 때: MySQL 데이터베이스 정리 도전기


데이터베이스 유지보수는 특히 대용량 트랜잭션 데이터를 다룰 때 결코 쉬운 일이 아닙니다. 최근 우리는 220 GB까지 부풀어 오른 MySQL 데이터베이스를 정리하는 작업을 맡았습니다. 목표는 간단했습니다: 2018‑2023년 사이의 데이터를 네 개 테이블에서 삭제해 공간을 회복하고 성능을 향상시키는 것이었습니다.
하지만 모든 개발자가 알듯이, “간단한” 작업에는 복잡한 함정이 숨어 있는 경우가 많습니다. 여기서는 저장소 한계와 기술적 장애물을 어떻게 극복하고 작업을 완수했는지 설명합니다.
도전 과제: 방 안의 200 GB “코끼리”

총 220 GB 중에서, 단일 테이블이 200 GB를 차지하고 있었습니다. 이 테이블은 트랜잭션 레코드와—실제 원인인—BLOB 첨부 파일들로 무겁게 구성되어 있었습니다. 우리의 목표는 2024년 이후 데이터만 남기는 것이었습니다.
Phase 1: “클론 및 스와프” 전략 (이상적인 계획)
- Clone – 기존 테이블을 새 이름으로 복사합니다.
- Filter – 2024년 현재 데이터만 새 테이블에 삽입합니다.
- Swap – 원본 테이블의 이름을 바꾸고 새 테이블로 교체합니다.
- Cleanup – 검증이 완료되면 오래된 테이블을 삭제합니다.
Pros: 안전합니다; 원본 데이터는 체크포인트로 그대로 유지됩니다.
Result in Dev: 완벽합니다. 백업 및 복원에 시간이 걸렸지만 예상대로 정확히 작동했습니다.
프로덕션 현실 점검
프로덕션으로 이동했을 때, 우리는 벽에 부딪혔습니다. 프로덕션 서버는 총 500 GB 용량을 가지고 있었지만, 남은 자유 공간은 100 GB에 불과했습니다. 200 GB 테이블을 100 GB 공간에 복제하는 것은 수학적으로 불가능했습니다. 우리는 Plan B가 필요했습니다.
Source: …
Phase 2: “청크 삭제” 전략 (안전한 선택?)
우리는 보다 세분화된 접근 방식으로 전환했습니다: 기존 테이블에서 데이터를 직접 삭제하는 것입니다. 장시간 실행되는 쿼리나 데이터베이스 잠금을 방지하기 위해 다음 절차를 따랐습니다:
- 연도별 구간(2018년, 2019년 등)으로 데이터를 삭제합니다.
- Bash 스크립트를 사용해
LIMIT절을 포함한 청크 삭제를 자동화함으로써 시스템이 응답성을 유지하고 DB가 “멈추는” 상황을 피합니다.


함정: OPTIMIZE TABLE 역설
삭제는 성공했지만 MySQL은 DELETE 후에 파일 크기를 자동으로 축소하지 않습니다(“high water mark”와 데이터 단편화 때문). 실제로 100 GB 이상의 공간을 회복하려면 OPTIMIZE TABLE을 실행해야 했습니다.
중대한 간과: OPTIMIZE TABLE은 테이블의 임시 복사본을 생성합니다. 데이터를 절반만 삭제했더라도 전체 테이블을 다시 쓰기 위해 충분한 여유 공간이 필요합니다. 우리의 100 GB 여유 공간이 다시 병목이 되었고, 우리는 교착 상태에 빠졌습니다.
Phase 3: “오프‑사이트 수술” (최종 해결책)
절박한 상황에서는 창의적인 아키텍처가 필요합니다. 우리는 별도의 환경에서 무거운 작업을 수행했습니다.
- Export – 거대한 200 GB 테이블을 덤프하고 충분한 저장 공간이 있는 보조 서버로 이동했습니다.
- Cleanse & Shrink – 보조 서버에서 원하지 않는 행을 삭제하고
OPTIMIZE TABLE을 실행했습니다. - Result – 최적화된 테이블 크기가 크게 줄어 100 GB 이하가 되었습니다.
- Import – 이제 압축된 테이블을 새로운 이름으로 프로덕션으로 다시 전송했습니다.
- Final Swap – 새로운 테이블이 100 GB의 여유 공간에 맞게 되었으므로 원본과 교체하고 기존 200 GB 거대한 테이블을 삭제했습니다.
Source:
우리를 위한 주요 요점
- 여유 공간은 최고의 친구 – 마이그레이션을 계획하기 전에 항상
df -h를 확인하세요. 대부분의 MySQL 유지 관리 작업(OPTIMIZE나ALTER등)에는 가장 큰 테이블 크기의 2배에 해당하는 여유 공간이 필요합니다. - 신중하게 최적화 –
OPTIMIZE TABLE은 “무료” 작업이 아니라는 점을 기억하세요; 현재 테이블 크기만큼의 임시 저장소가 필요합니다. - 청크 단위 작업이 구원 – 데이터를 작은 배치로 삭제하면 긴 잠금을 방지하고 DB 응답성을 유지할 수 있습니다.
- 오프사이트 처리로 생존 – 온프레미스 저장소가 부족할 경우, 무거운 변환 작업을 더 큰 환경으로 오프로드하면 다운타임 없이 문제를 해결할 수 있습니다.
작성자: Taufiq Abdullah.
An “in‑place” fix; it is a rebuild.
**Think Outside the Box:**
If your local disk is full, use a secondary staging server to process the data before bringing it back home.
Database cleansing is as much about managing infrastructure as it is about writing SQL. Have you ever faced a storage “deadlock” like this? I’d love to hear how you handled it in the comments! 