도입
ALTER TABLE이 오래 끝나지 않으면 테이블이 커서 느린 것으로 생각하기 쉽다. 그러나 실행 시간은 0초인데 상태가 Waiting for table metadata lock이라면 작업은 시작조차 못 한 것이다. 다른 세션이 테이블의 메타데이터 잠금을 잡은 채 트랜잭션을 끝내지 않았기 때문이다.
이 글에서는 MariaDB 10.11과 InnoDB를 기준으로 대기 상황을 직접 만들고, blocker를 찾은 뒤 안전하게 해제한다. 운영 데이터베이스가 아닌 별도의 실습 DB에서 실행해야 한다.
1. 실습 테이블 준비
CREATE DATABASE IF NOT EXISTS mdl_lab;
USE mdl_lab;
CREATE TABLE orders (
order_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
status VARCHAR(20) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
INSERT INTO orders(status) VALUES ('paid'), ('ready');
터미널을 세 개 열고 각각 MariaDB에 접속한다.
mariadb --defaults-extra-file="$HOME/.my.cnf" mdl_lab
비밀번호를 -p비밀번호 형태로 명령행에 쓰지 않았다. 프로세스 목록과 셸 기록에 인증 정보가 남을 수 있기 때문이다.
2. 잠금 대기 재현
세션 A에서 트랜잭션을 열고 행을 읽는다.
START TRANSACTION;
SELECT * FROM orders WHERE order_id = 1;
SELECT가 끝나도 트랜잭션은 열려 있다. MariaDB는 트랜잭션이 사용한 테이블의 메타데이터 잠금을 트랜잭션 종료까지 유지한다.
세션 B에서 다음 DDL을 실행한다.
ALTER TABLE orders ADD COLUMN memo VARCHAR(100) NULL;
프롬프트가 돌아오지 않는다. 이 상태에서 같은 명령을 반복 실행하면 해결되지 않고 대기자만 늘어난다.
3. 기다리는 세션과 blocker 찾기
세션 C에서 먼저 프로세스 목록을 확인한다.
SHOW FULL PROCESSLIST;
확인할 열은 Id, User, Host, db, Time, State, Info다. 세션 B의 State가 다음처럼 표시된다.
Waiting for table metadata lock
장시간 Sleep인 연결도 무조건 제거하면 안 된다. 열린 트랜잭션인지 확인한다.
SELECT
trx_mysql_thread_id,
trx_started,
trx_state,
trx_tables_locked,
trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started;
trx_mysql_thread_id를 PROCESSLIST.Id와 연결하면 오래된 트랜잭션의 세션을 찾을 수 있다. Performance Schema가 활성화된 환경에서는 보조적으로 다음 정보를 확인한다.
SELECT *
FROM performance_schema.metadata_locks
WHERE OBJECT_SCHEMA = 'mdl_lab'
AND OBJECT_NAME = 'orders';
환경에 따라 metadata_locks의 계측 상태나 표시 내용이 다를 수 있으므로, PROCESSLIST와 innodb_trx를 함께 보는 편이 안전하다.
4. 안전한 해제 순서
가장 좋은 해결은 세션 A에서 업무 로직에 맞게 트랜잭션을 끝내는 것이다.
ROLLBACK;
변경을 보존해야 한다면 COMMIT한다. 잠금이 풀리면 세션 B의 ALTER TABLE이 진행된다.
SHOW COLUMNS FROM orders LIKE 'memo';
원래 세션에 접근할 수 없고 서비스 영향이 계속되는 경우에만 관리 세션에서 종료를 검토한다.
KILL QUERY 1234; -- 현재 문장만 중단
KILL CONNECTION 1234; -- 연결과 트랜잭션 종료
여기서 1234는 반드시 다시 확인한 실제 연결 ID여야 한다. 쓰기 트랜잭션을 KILL CONNECTION으로 종료하면 rollback이 오래 걸릴 수 있다. 담당자와 쿼리, 트랜잭션 시작 시각, 변경량을 확인한 뒤 결정한다.
5. 무한정 기다리지 않게 만들기
MariaDB의 lock_wait_timeout 기본값은 매우 길 수 있다. 유지보수 세션에서만 짧게 제한할 수 있다.
SET SESSION lock_wait_timeout = 10;
ALTER TABLE orders ADD COLUMN reviewed_at DATETIME NULL;
문장 단위로 즉시 실패시키려면 NOWAIT를 사용한다.
ALTER TABLE orders NOWAIT ADD COLUMN reviewed_by BIGINT NULL;
NOWAIT는 잠금을 해결하는 기능이 아니다. 기다리지 않고 실패시켜 배포 자동화가 빠르게 중단되도록 만드는 안전장치다.
운영 점검 체크리스트
- DDL 전에 오래 열린 트랜잭션을 확인했는가?
PROCESSLIST의 대기 세션과innodb_trx의 blocker를 연결했는가?- 세션 종료 전에 정상적인
COMMIT또는ROLLBACK을 요청했는가? - 연결 ID, 사용자, 호스트와 실행 SQL을 재확인했는가?
- 배포용 계정의 세션에 적절한
lock_wait_timeout을 설정했는가? - 스키마 변경 실패 시 재시도·중단 절차가 있는가?
함께 읽기
참고 자료
확인일: 2026-07-29
한 줄 요약
멈춘 ALTER TABLE은 반복 실행하지 말고, 대기 세션과 열린 트랜잭션을 연결해 blocker를 찾은 뒤 정상 종료부터 시도한다.
댓글 0