ALTER TABLE이 멈췄을 때 — MariaDB Metadata Lock 재현·증거 수집·안전한 해제

조회수 66

도입

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;
세션 A에서 START TRANSACTION 실행 후 orders 테이블 SELECT 결과
세션 A가 트랜잭션을 열고 orders 테이블에 접근한 채 대기 중이다.

세션 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.Idtrx_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 계측 상태에 따라 결과가 다를 수 있으므로 이것만으로 판정하지 않는다.

MariaDB에서 Metadata Lock 대기 세션과 열린 트랜잭션을 연결한 출력
대기 연결 ID와 열린 트랜잭션의 연결 ID를 함께 확인한다.

안전한 해제 순서

  1. 배포·장애 담당자에게 대기 DDL과 blocker 후보를 알린다.
  2. 원래 연결에서 업무 의미에 맞게 COMMIT 또는 ROLLBACK한다.
  3. 접근할 수 없고 영향이 지속될 때만 관리 연결에서 종료를 검토한다.
  4. 종료 직전에 연결 ID, 사용자, 호스트와 트랜잭션을 다시 조회한다.
  5. 해제 후 DDL 결과와 애플리케이션 오류를 확인한다.
-- 우선 세션 A에서 실행
ROLLBACK;

-- 불가피한 경우에만 관리 연결에서 실제 ID로 실행
KILL QUERY 1234;
KILL CONNECTION 1234;
세션 A에서 ROLLBACK 실행 결과
세션 A에서 ROLLBACK을 실행해 열린 트랜잭션을 해제한다.
ROLLBACK 후 세션 B의 ALTER TABLE이 완료된 출력
ROLLBACK 직후 대기 중이던 ALTER TABLE이 약 14초 만에 완료됐다.

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);
SHOW COLUMNS에서 memo 컬럼 추가 확인
SHOW COLUMNS에서 memo 컬럼이 확인되면 DDL이 정상 적용된 것이다.

컬럼 존재 여부, 대기 세션 소멸과 애플리케이션 쿼리 성공을 함께 확인한다. 제한 시간으로 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

  • 첫 번째 댓글을 남겨보세요.