도입
ALTER TABLE이 끝나지 않을 때 테이블 크기만 의심하면 원인을 놓칠 수 있다. Waiting for table metadata lock 상태라면 다른 세션의 열린 트랜잭션 때문에 DDL이 시작되지 못한 것이다. 이 글은 MariaDB 10.11과 InnoDB의 별도 실습 DB에서 대기를 재현하고, 종료할 세션을 추측하지 않고 증거로 판정하는 절차를 다룬다.
1. 실습 환경과 완료 조건
SELECT VERSION();
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');
세 개의 연결을 준비한다. 완료 조건은 세션 B의 대기 상태, 세션 A의 열린 트랜잭션과 두 세션의 연결 ID를 기록하고, 정상적인 ROLLBACK 후 DDL 적용 여부까지 확인하는 것이다.
실무 기준 / 적용 방법
대기 상황 재현
세션 A:
SELECT CONNECTION_ID() AS session_a;
START TRANSACTION;
SELECT * FROM orders WHERE order_id = 1;
세션 B:
SELECT CONNECTION_ID() AS session_b;
SET SESSION lock_wait_timeout = 30;
ALTER TABLE orders ADD COLUMN memo VARCHAR(100) NULL;
lock_wait_timeout은 blocker를 해결하지 않는다. 유지보수 작업이 무한정 대기하지 않고 실패하도록 세션 범위에 제한을 둔다.
세션 C에서 증거 수집
SHOW FULL PROCESSLIST;
SELECT
trx_mysql_thread_id,
trx_started,
trx_state,
trx_tables_locked,
trx_rows_modified,
trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started;
PROCESSLIST.Id와 trx_mysql_thread_id를 연결한다. 오래 Sleep이라는 이유만으로 blocker라고 단정하지 않는다. 사용자, 호스트, DB, 트랜잭션 시작 시각과 변경 행 수를 함께 기록한다.
SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION,
LOCK_STATUS, OWNER_THREAD_ID
FROM performance_schema.metadata_locks
WHERE OBJECT_SCHEMA = 'mdl_lab'
AND OBJECT_NAME = 'orders';
Performance Schema 계측 상태에 따라 결과가 다를 수 있으므로 이것만으로 판정하지 않는다.
안전한 해제 순서
- 배포·장애 담당자에게 대기 DDL과 blocker 후보를 알린다.
- 원래 연결에서 업무 의미에 맞게
COMMIT또는ROLLBACK한다. - 접근할 수 없고 영향이 지속될 때만 관리 연결에서 종료를 검토한다.
- 종료 직전에 연결 ID, 사용자, 호스트와 트랜잭션을 다시 조회한다.
- 해제 후 DDL 결과와 애플리케이션 오류를 확인한다.
-- 우선 세션 A에서 실행
ROLLBACK;
-- 불가피한 경우에만 관리 연결에서 실제 ID로 실행
KILL QUERY 1234;
KILL CONNECTION 1234;
KILL QUERY와 연결 종료의 영향은 다르다. 쓰기 트랜잭션 연결을 종료하면 rollback 자체가 오래 걸릴 수 있다. 예제 ID를 복사해 운영에서 실행하지 않는다.
해결 결과 검증
SHOW COLUMNS FROM mdl_lab.orders LIKE 'memo';
SHOW FULL PROCESSLIST;
SELECT *
FROM information_schema.innodb_trx
WHERE trx_mysql_thread_id IN (1234, 1235);
컬럼 존재 여부, 대기 세션 소멸과 애플리케이션 쿼리 성공을 함께 확인한다. 제한 시간으로 DDL이 실패했다면 현재 스키마를 확인한 뒤 재실행 여부를 결정한다.
6. 장애 기록 양식
MariaDB 버전:
발생·해제 시각:
대기 DDL과 connection ID:
blocker connection ID / user / host:
트랜잭션 시작 시각과 변경 행 수:
선택한 종료 방법과 승인자:
rollback 소요 시간:
DDL 최종 결과:
재발 방지 작업:
7. 재발 방지
- 요청 종료 시 열린 트랜잭션이 남지 않도록 commit·rollback 경계를 테스트한다.
- DDL 전에 오래 열린 트랜잭션과 변경 작업을 확인한다.
- 배포 계정 세션에 제한된 대기 시간을 적용한다.
- 같은 DDL을 자동으로 무한 재시도하지 않는다.
- 연결 ID만이 아니라 사용자·호스트·SQL을 포함한 승인 절차를 둔다.
참고: MariaDB Metadata Locking, ALTER TABLE, WAIT/NOWAIT 공식 문서. 확인일 2026-08-11.
한 줄 요약
멈춘 DDL은 반복 실행하지 말고 대기 연결과 열린 트랜잭션을 증거로 연결한 뒤 원래 세션의 정상 종료부터 시도한다.
댓글 0