카카오 「MySQL ALTER DDL 수행 방식에 대한 이해」 리뷰 — Copy·In-Place·Instant는 '무엇을 복사하느냐'보다 '언제 Exclusive 메타 락을 잡느냐'로 구분된다
원문: MySQL ALTER DDL 수행 방식에 대한 이해 — kakao tech, 2025-05-14
한 줄 요약
MySQL의 ALTER는 세 알고리즘으로 돈다. Copy(새 테이블에 전부 복사, 쓰기 차단), In-Place(5.6+, 임시 구조와 DML 로그로 읽기·쓰기 허용, 필요 시 리빌드), Instant(8.0+, 메타데이터만 수정). 원문은 소스 코드 수준에서 ALTER의 3단계(Initialization → Execution → Final)와 세 핵심 함수(ha_prepare_inplace_alter_table, ha_inplace_alter_table, ha_commit_inplace_alter_table)를 따라가며 어느 시점에 어떤 메타데이터 락을 잡는지를 비교한다. 핵심 발견은 In-Place가 prepare 전과 commit 전 두 번 Exclusive 락을 잡고, Instant는 commit 전 한 번만 잡는다는 것, 그리고 메타데이터만 바꾸는 작업이라도 In-Place로 지정하면 두 번 잡는다는 것이다. 결론은 습관 둘: ALGORITHM을 명시하라, 실행 전 장기 트랜잭션을 확인하라.
배경
MySQL은 서비스가 커질수록 운영이 어려웠고, 그중 하나가 서비스 중 Online DDL이다. 5.6에서 In-Place가 추가돼 가용성이 올라갔지만, 시작과 끝에 메타 락이 필요하고 작업에 따라 임시 테이블과 복사도 필요해 편하지는 않았다. 8.0의 Instant까지 셋을 이해해야 운영에서 사고를 피한다.
ALTER의 3단계
Initialization. 사용자가 지정한 알고리즘으로 가능한지 확인하고(컬럼명 중복 등 메타데이터만으로 알 수 있는 것), handler::check_if_supported_inplace_alter()로 필요한 락 모드를 얻어 사용자가 지정한 LOCK=과 충돌하면 오류로 중단한다.
Execution. 실제 작업. 메타데이터 락 네 가지를 알아야 한다.
| 락 | 의미 |
|---|---|
MDL_SHARED_UPGRADABLE | 승격 가능한 공유 락. 다른 세션의 읽기·쓰기 허용 |
MDL_SHARED_READ | 읽기용 공유 락 |
MDL_SHARED_NO_WRITE | 다른 세션의 읽기는 허용, 쓰기는 차단 |
MDL_EXCLUSIVE | 모든 접근 차단 |
순서는 이렇다. ① MDL_SHARED_UPGRADABLE 획득. ② In-Place면 MDL_EXCLUSIVE로 승격. ③ ha_prepare_inplace_alter_table()로 제약 검사, 인덱스·외래키 메타데이터 갱신(Instant는 건너뜀). ④ In-Place면 다시 강등. DDL 중 DML을 막아야 하면 SHARED_NO_WRITE, 아니면 SHARED_UPGRADABLE. ⑤ ha_inplace_alter_table()로 실제 변경(Instant는 건너뜀). ⑥ MDL_EXCLUSIVE로 승격 후 ha_commit_inplace_alter_table()로 메타데이터 변경.
Final. Data Dictionary 갱신과 커밋. atomic DDL을 지원하는 엔진은 테이블 이름 교체를 먼저 하고 DD를 갱신·커밋하며, 아닌 엔진은 반대다. 마지막에 MDL_SHARED_READ로 메타데이터를 확인하고 정리한다.
세 함수
- prepare: 인덱스 이름·컬럼 이름 제약을 검사하고 인덱스·외래키 메타데이터를 갱신. Instant는 아무것도 안 하고 빠져나온다.
- inplace_alter: 테이블 리빌드, DML 로그 적용, 인덱스 구성. Instant이거나, In-Place라도 인덱스 구성이 아니고 리빌드도 필요 없으면 아무것도 안 한다.
- commit: 임시 이름 생성, 통계 스레드 접근 차단, 원본과 새 테이블 메타데이터 동기화. Instant는
dd_add_instant_columns로row_version을 올리고 DEFAULT 값을 설정한다.
세 알고리즘
Copy. 가장 오래되고 단순하다. DDL이 적용된 새 테이블을 만들고 → 데이터를 복사하고 → 이름을 바꾸고 옛 테이블을 지운다. 읽기는 되지만 쓰기는 끝날 때까지 막힌다. 8.0 기준 PK 삭제, 컬럼 타입 변경, 문자셋 변환은 Copy로만 된다. 디스크 공간·I/O·시간이 테이블 크기에 비례하고 복제 지연을 만들며 롤백도 오래 걸린다.
In-Place. 5.6에서 추가. 대부분의 작업에서 읽기·쓰기가 되고 필요하면 리빌드한다. 리빌드 기준으로 임시 테이블 생성 → 데이터 복사(타입 변환 포함) → 복사 중 유입된 쓰기는 별도 버퍼에 DML 로그로 적재 → 복사가 끝나면 DML 로그 적용 → 이름 교체. 원문의 내부 테스트로는 이 임시 테이블 작업이 Copy의 전체 복사와는 다른 것으로 추정되며 더 빠르다. 단점은 여전히 크기에 비례하는 시간, 일부 작업의 쓰기 차단, 높은 I/O, 복제 지연, Exclusive 메타 락 2회, innodb_online_alter_log_max_size(DML 로그 상한)를 잘못 잡으면 실패한다는 것.
Instant. 8.0.12에서 추가. 메타데이터만 바꾸고 row_version을 올린다. 컬럼 추가/삭제, DEFAULT 설정, ENUM 명세 변경을 지원하며 확대 중이다(컬럼 추가 외는 8.0.29부터). 단점은 지원 작업이 적고, 64번까지만 가능하며 그 뒤에는 리빌드가 필요하고, FULLTEXT 인덱스나 ROW_FORMAT=COMPRESSED 테이블에서는 컬럼 추가/삭제가 안 되며, Exclusive 락이 짧게 1회 있다는 것.
| Copy | In-Place | Instant | |
|---|---|---|---|
| 테이블 복사 | 예 | 부분적(내부 중간 구조) | 아니오 |
| 동시 DML | 아니오 | 작업에 따라 | 예 |
| 디스크 오버헤드 | 높음 | 중간(임시 파일·로그) | 매우 낮음 |
| 시간 | 가장 느림 | 작업·크기에 따라 | 가장 빠름 |
| 버전 | 모두 | 5.6+ | 8.0.12+ |
핵심: 메타 락 비교
두 알고리즘 모두 MDL_SHARED_UPGRADABLE로 시작하니 그 단계까지는 다른 세션에 영향이 없다. 차이는 다음이다.
- prepare 전: In-Place만
MDL_EXCLUSIVE로 승격한다. 이때부터 다른 세션이 메타 락 대기에 빠질 수 있다. prepare가 끝나면 다시 강등한다. - inplace_alter 중: 둘 다
SHARED_UPGRADABLE. Instant이거나 In-Place 중 리빌드·인덱스가 아니면 이 안에서 하는 일이 없다. - commit 전: 둘 다
MDL_EXCLUSIVE로 승격하고 commit 함수가 끝날 때까지 다른 세션을 막는다. - Final:
MDL_SHARED_READ.
예외로 AUTO_INCREMENT INT 컬럼 추가는 In-Place에서 SHARED_UPGRADABLE이 아니라 SHARED_NO_WRITE로 강등한다.
그리고 궁금할 만한 실험 하나. In-Place로도 메타데이터만 수정하는 작업이 있는데, 그러면 Instant와 같지 않을까? 디버깅해 보니 아니다. 소스가 알고리즘만 보고 승격을 결정하므로 메타데이터만 바꾸는 작업이라도 In-Place면 prepare 전에 MDL_EXCLUSIVE를 잡는다. 즉 Exclusive 락 횟수는 작업 내용이 아니라 지정한 알고리즘이 정한다.
결론: 두 가지 습관
작업에 따라 쓸 수 있는 알고리즘이 정해져 있어 선택의 폭은 좁다. 그래도 어떤 경우든 ALGORITHM 구문을 명시하라. 그래야 예기치 않게 느린 알고리즘으로 대체되는 것을 막는다(지정한 알고리즘이 불가능하면 오류로 멈추므로 방어적이다). 그리고 어떤 DDL이든 Exclusive 메타 락이 짧게라도 들어가므로 실행 전 장기 실행 트랜잭션·쿼리가 없는지 확인하라. 하나라도 있으면 그 뒤의 모든 세션이 줄줄이 대기한다.
읽고 남는 질문
- Instant의 64회 제한이 실제 운영에서 얼마나 빨리 닿는지, 닿았을 때의 리빌드를 어떻게 스케줄하는지가 궁금하다. 컬럼 추가가 잦은 테이블은 생각보다 빨리 닿을 수 있다.
- In-Place의 “임시 테이블 작업이 Copy의 전체 복사와 다른 것으로 추정”은 추정에 그친다. 크기가 큰 테이블에서 실제 소요 시간과 디스크 사용량을 비교한 수치가 있으면 좋겠다.
LOCK=NONE을 명시하는 것도ALGORITHM명시만큼 중요한 방어인데(지원 안 되면 오류로 멈춤), 결론에 같이 언급됐으면 완결성이 있었을 것이다.
한 줄로 가져가기
Online DDL의 위험은 복사 시간이 아니라 승격되는 Exclusive 메타 락의 순간이다. In-Place는 두 번, Instant는 한 번이고, 그 순간에 긴 트랜잭션이 하나라도 있으면 서비스 전체가 그 뒤에 줄을 선다.
댓글
아직 댓글이 없습니다