컨텐츠로 건너뛰기

KhoonLabs DB – 데이터베이스 기술과 실전 운영

  • 홈
  • Oracle
  • DB 운영
  • SQL 실무
  • 성능 튜닝
  • 장애 해결
  • 미분류
메타데이터 락 때문에 온라인 DDL 작업이 대기하는 과정을 표현한 일러스트

MySQL 8.4 ONLINE DDL이 LOCK=NONE인데 멈출 때: metadata lock 차단 세션 찾는 순서

2026년 08월 14일 작성자: aloloever

MySQL 8.4에서 ALTER TABLE ... LOCK=NONE을 실행했는데도 명령이 시작하지 않거나 마지막에 멈춘 듯 보이면, 먼저 메타데이터 락(MDL)을 의심해야 합니다. LOCK=NONE은 해당 InnoDB 작업 중 읽기와 쓰기를 허용하겠다는 요청이지, DDL이 테이블 정의를 바꾸기 위해 필요한 메타데이터 락까지 없앤다는 뜻은 아닙니다.

이 글은 InnoDB 테이블에서 온라인 DDL을 배포할 때, 대기 중인 ALTER TABLE과 이를 막는 세션을 찾고, 섣불리 세션을 끊지 않고 안전하게 다음 행동을 정하는 방법을 다룹니다. 예시는 MySQL 8.4 기준이며, 운영 서버에서 실행 전에는 권한과 배포 중단 기준을 확인해야 합니다.

핵심 답변

LOCK=NONE이어도 오래 열린 트랜잭션이나 테이블을 참조한 세션이 MDL을 잡고 있으면 ALTER TABLE은 대기합니다. 먼저 sys.schema_table_lock_waits에서 기다리는 PID와 차단 PID를 확인하고, 차단 세션의 업무·트랜잭션 상태를 확인한 뒤 정상 종료를 기다리는 것이 기본입니다. 잠깐의 배타적 락은 작업의 시작·마지막 단계에도 필요할 수 있으므로, 무중단을 보장하는 옵션으로 해석하면 안 됩니다.

적용 범위와 먼저 볼 것

항목 적용·확인 내용 운영 영향 또는 예외
대상 MySQL 8.4, InnoDB, ALTER TABLE 온라인 작업 세부 작업마다 허용되는 ALGORITHM·LOCK 조합이 다릅니다.
첫 진단 sys.schema_table_lock_waits에서 waiting/blocking PID를 찾습니다. sys 스키마와 Performance Schema 정보가 보여야 합니다.
즉시 중단 기준 차단자가 업무 트랜잭션·백업·복제 작업인지 확인되지 않았을 때 PID만 보고 KILL하면 롤백과 서비스 오류를 유발할 수 있습니다.
DDL 옵션 ALGORITHM=INPLACE, LOCK=NONE을 명시해 허용되지 않는 강한 방식은 실패하게 만듭니다. INSTANT 작업에는 LOCK=DEFAULT만 지원됩니다.

왜 LOCK=NONE인데 대기하는가

InnoDB 온라인 DDL은 테이블을 항상 완전히 잠그지 않고 변경하려는 기능입니다. 예를 들어 보조 인덱스를 추가하는 일부 작업은 in-place 방식으로 수행하면서 동시 DML을 허용합니다. 이때 LOCK=NONE을 붙이면 읽기와 쓰기를 막지 않는 수준의 동시성을 MySQL에 요구합니다. 요청한 수준을 지원하지 않는 작업이면 조용히 더 강한 락으로 바꾸는 대신 오류로 멈춥니다.

하지만 SQL 문이 테이블 정의를 변경하려면 서버가 다른 세션과 정의 변경 순서를 맞춰야 합니다. 이 조정에 쓰는 것이 MDL입니다. 세션 A가 테이블을 읽고 트랜잭션을 오래 열어 둔 상태라면, 세션 B의 DDL은 필요한 MDL을 얻을 때까지 기다릴 수 있습니다. DDL이 줄의 앞에 서면 이후에 같은 테이블을 열려는 세션도 함께 밀릴 수 있어, 단순히 DDL 하나가 느린 문제로 끝나지 않을 수 있습니다.

온라인 DDL에는 시작과 완료 직전에 짧은 배타적 락이 필요할 수 있습니다. 공식 문서도 이 대기 때문에 타임아웃이 발생할 수 있다고 설명합니다. 따라서 LOCK=NONE은 배포 계획을 세우는 좋은 안전장치이지만, 장기 트랜잭션·커넥션 풀의 미종료 세션·긴 조회를 대신 관리해 주지는 않습니다.

최소 재현: 열린 트랜잭션 뒤에서 ALTER TABLE이 기다리는 모습

아래는 테스트 전용 예시입니다. 터미널을 두 개 열어 세션 A와 세션 B에서 나누어 실행합니다. 실제 운영 테이블과 이름이 겹치지 않는 별도 스키마를 사용하십시오.

CREATE DATABASE IF NOT EXISTS ddl_lab;
USE ddl_lab;

CREATE TABLE orders (
  order_id BIGINT NOT NULL,
  customer_id BIGINT NOT NULL,
  ordered_at DATETIME NOT NULL,
  status VARCHAR(20) NOT NULL,
  PRIMARY KEY (order_id)
) ENGINE=InnoDB;

INSERT INTO orders (order_id, customer_id, ordered_at, status)
VALUES (1, 101, NOW(), 'PAID');

실행 목적

권한: 테스트 스키마 생성·테이블 생성·행 삽입 권한이 필요합니다. 적용 버전: MySQL 8.4 InnoDB. 예상 결과: 인덱스가 없는 작은 테스트 테이블과 한 행이 만들어집니다. 이 코드는 운영 테이블에 실행하는 변경문이 아닙니다.

세션 A에서는 행을 읽은 뒤 커밋하지 않습니다. 행 자체를 수정하지 않아도, 트랜잭션 안에서 테이블을 참조한 상태가 DDL과 충돌하는지 확인하는 재현 재료가 됩니다.

USE ddl_lab;
START TRANSACTION;

SELECT order_id, customer_id, ordered_at, status
FROM orders
WHERE order_id = 1;

-- 이 세션은 COMMIT 또는 ROLLBACK 전까지 열어 둡니다.

실행 목적

권한: ddl_lab.orders에 대한 SELECT 권한. 예상 결과: 세션 A가 트랜잭션을 유지합니다. 실제 관찰 결과는 격리 수준과 세션 상태에 따라 달라질 수 있으므로, 다음 진단 SQL로 대기 관계를 확인합니다.

세션 B에서 인덱스를 추가합니다. ALGORITHM=INPLACE, LOCK=NONE은 이 예제 작업이 요청한 온라인 방식으로 불가능하면 강한 락으로 전환하지 않고 실패하도록 만듭니다.

USE ddl_lab;

ALTER TABLE orders
  ADD INDEX ix_orders_customer_ordered (customer_id, ordered_at),
  ALGORITHM=INPLACE,
  LOCK=NONE;

운영 환경 주의

ALTER TABLE은 자동 커밋되는 DDL입니다. 운영 서버에서는 이 예제를 복사해 바로 실행하지 말고, 대상 작업이 INPLACE·LOCK=NONE을 지원하는지 공식 온라인 DDL 표에서 먼저 확인하십시오. DDL이 대기 중일 때 무작정 재시도하거나 옵션을 빼면 COPY 방식이나 더 강한 잠금으로 바뀌는 위험이 있습니다.

실행 목적

권한: 대상 테이블에 대한 ALTER 권한. 예상 결과: 세션 A가 끝나면 인덱스가 추가됩니다. 대기가 보이지 않거나 즉시 끝날 수도 있으므로 재현 성공 여부보다 대기 관계를 읽는 절차에 초점을 맞추십시오.

대기와 차단 세션을 찾는 순서

가장 짧은 출발점은 sys 스키마의 schema_table_lock_waits 뷰입니다. 이 뷰는 메타데이터 락을 기다리는 세션과 이를 막는 세션을 함께 보여 줍니다. 애플리케이션 로그의 커넥션 ID나 배포 도구의 PID와 연결하기도 쉽습니다.

SELECT
  object_schema,
  object_name,
  waiting_pid,
  waiting_query,
  blocking_pid,
  blocking_account,
  blocking_query
FROM sys.schema_table_lock_waits
WHERE object_schema = 'ddl_lab'
  AND object_name = 'orders';

실행 목적

권한: sys 뷰와 그 기반 Performance Schema 정보를 볼 권한이 필요합니다. 권한 설계는 조직마다 다르므로 운영 계정에 광범위한 권한을 새로 부여하지 말고 DBA용 읽기 전용 계정을 사용하십시오. 예상 결과: 대기 중이면 waiting_pid와 blocking_pid, 두 SQL의 일부가 나옵니다. 빈 결과는 그 순간 MDL 대기가 없거나 관측 정보가 부족하다는 뜻입니다.

이 결과에서 중요한 것은 대기 PID가 아니라 차단 PID의 성격입니다. 차단 쿼리가 긴 SELECT인지, 아직 커밋하지 않은 쓰기 트랜잭션인지, 백업·관리 작업인지 구분해야 합니다. 같은 PID의 상세 상태를 볼 때는 필요한 열만 조회합니다.

SELECT
  p.ID,
  p.USER,
  p.HOST,
  p.DB,
  p.COMMAND,
  p.TIME,
  p.STATE,
  p.INFO
FROM information_schema.PROCESSLIST AS p
WHERE p.ID IN (/* waiting_pid, blocking_pid를 숫자로 넣습니다 */);

실행 목적

권한: 다른 세션을 보려면 PROCESS 권한 또는 이에 준하는 관측 권한이 필요합니다. 예상 결과: 세션의 사용자·호스트·실행 시간·상태·현재 SQL을 비교합니다. INFO에는 민감한 값이 포함될 수 있으므로 운영 로그로 내보낼 때는 마스킹 정책을 따르십시오.

sys 뷰가 비어 있거나 더 낮은 수준의 확인이 필요할 때

Performance Schema의 metadata_locks에는 held·requested 메타데이터 락 정보가 있습니다. 다만 이 테이블을 직접 조인해 차단 관계를 추정하는 SQL은 MySQL 버전·관측 설정에 따라 읽기 어렵고 실수하기 쉽습니다. 먼저 sys 뷰를 사용하고, 결과가 비어 있는데 DDL이 계속 기다린다면 Performance Schema가 켜져 있는지와 메타데이터 락 관측 한도를 DBA와 확인하는 편이 안전합니다.

SELECT
  OBJECT_TYPE,
  OBJECT_SCHEMA,
  OBJECT_NAME,
  LOCK_TYPE,
  LOCK_DURATION,
  LOCK_STATUS,
  OWNER_THREAD_ID
FROM performance_schema.metadata_locks
WHERE OBJECT_SCHEMA = 'ddl_lab'
  AND OBJECT_NAME = 'orders'
ORDER BY OWNER_THREAD_ID, LOCK_STATUS;

실행 목적

권한: Performance Schema 읽기 권한. 예상 결과: 대상 객체의 GRANTED와 PENDING 락을 확인합니다. 해석: PENDING 하나만 보고 차단자를 단정하지 말고, 같은 시점의 sys 뷰·프로세스 목록·애플리케이션 배포 기록과 함께 판단합니다.

작업 전·후 검증표

시점 확인 판단·다음 행동
DDL 전 변경 종류가 INPLACE·LOCK=NONE 조합을 지원하는지 확인 지원하지 않으면 운영 창·대체 배포 방식을 다시 정합니다.
대기 발생 waiting/blocking PID와 차단 SQL, 업무 소유자를 확인 정상 종료 가능 여부를 소유자와 판단합니다.
DDL 완료 인덱스 정의와 애플리케이션 오류·대기열을 확인 예상과 다르면 배포 후속 변경을 멈추고 영향 범위를 좁힙니다.
SELECT
  INDEX_NAME,
  SEQ_IN_INDEX,
  COLUMN_NAME,
  NON_UNIQUE
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = 'ddl_lab'
  AND TABLE_NAME = 'orders'
ORDER BY INDEX_NAME, SEQ_IN_INDEX;

실행 목적

권한: INFORMATION_SCHEMA에서 대상 테이블 메타데이터를 읽을 권한. 예상 결과: ix_orders_customer_ordered와 두 컬럼의 순서가 보입니다. 인덱스가 존재한다는 사실만으로 성능 개선을 보장하지 않으므로, 실제 쿼리의 실행계획과 데이터 분포는 별도로 확인합니다.

세션 종료는 마지막 수단으로 둔다

차단 세션이 명백히 종료되어야 할 유휴 작업이고, 업무 소유자가 종료를 승인했으며, 롤백 시간과 애플리케이션 영향까지 확인한 경우에만 세션 종료를 검토합니다. 특히 쓰기 트랜잭션을 끊으면 InnoDB가 롤백을 수행하며, 이 시간이 DDL 대기보다 길어질 수 있습니다. 커넥션 풀은 끊긴 세션을 다시 만들 수 있으므로 애플리케이션 쪽의 재시도·오류 처리도 함께 봐야 합니다.

운영 환경 주의

KILL 12345는 문제 해결용 기본 SQL이 아닙니다. 차단 PID가 실제로 대상 테이블의 MDL을 잡고 있는지, 트랜잭션이 어떤 업무에 속하는지, 종료 뒤 롤백과 재연결을 감당할 수 있는지 확인되지 않았다면 실행하지 마십시오. 우선 업무가 정상적으로 COMMIT 또는 ROLLBACK 하도록 조정하고, 불가피한 긴급 조치는 조직의 장애 절차와 승인 아래 수행합니다.

대기 중인 DDL을 취소해야 한다면, 배포 도구가 제공하는 취소 절차를 먼저 사용하고 현재 상태를 다시 조회합니다. DDL이 실패했다고 해서 인덱스나 테이블 정의가 항상 같은 상태로 남는 것은 아닙니다. 인덱스 추가 작업이 끝까지 가지 못했을 때는 재시도 전에 information_schema.STATISTICS로 실제 정의를 확인합니다.

자주 하는 오해

  • LOCK=NONE이면 락이 없다. DML 동시성 요청과 MDL 대기는 다른 문제입니다. 시작·완료 단계의 짧은 배타적 락도 고려해야 합니다.
  • 대기 중인 ALTER만 죽이면 끝난다. 차단 세션이 남아 있으면 다음 배포도 같은 곳에서 멈춥니다. 먼저 blocker를 식별해야 합니다.
  • 차단 PID는 바로 KILL한다. 장기 트랜잭션의 롤백, 업무 오류, 커넥션 풀 재연결을 고려하지 않은 종료는 장애를 키울 수 있습니다.
  • ALGORITHM과 LOCK 옵션을 생략해도 같다. 명시하지 않으면 작업 종류와 서버 판단에 따라 예상보다 강한 방식이 선택될 여지가 있습니다. 운영 배포에서는 허용 가능한 방식을 옵션으로 고정해 실패를 빠르게 드러내는 편이 안전합니다.
  • DDL 완료 후 인덱스 존재만 보면 된다. 정의 확인 뒤 실제 쿼리 실행계획, 오류율, 대기열을 함께 관찰해야 합니다.

마무리

온라인 DDL의 목표는 테이블을 바꾸는 동안 동시 작업을 최대한 허용하는 것입니다. 그러나 그 목표가 메타데이터 락 대기까지 없애지는 않습니다. 배포가 멈춘 순간에는 옵션을 바꾸거나 세션을 끊기 전에 sys.schema_table_lock_waits로 waiting PID와 blocking PID를 연결하고, 차단 세션의 업무 맥락을 확인하십시오. 이 순서가 있어야 온라인 DDL을 단순한 문법이 아니라 안전한 운영 절차로 쓸 수 있습니다.

공식 출처

  • MySQL 8.4 Reference Manual — InnoDB and Online DDL
  • MySQL 8.4 Reference Manual — Online DDL Failure Conditions
  • MySQL 8.4 Reference Manual — schema_table_lock_waits
  • MySQL 8.4 Reference Manual — Performance Schema Lock Tables
카테고리 DB 운영 태그 ALTER TABLE, metadata lock, MySQL 8.4, Performance Schema, 온라인 DDL
Oracle 19c ORA-00060 데드락 trace 읽기: 원인 SQL을 찾고 재발을 막는 순서
Oracle 19c Flashback Query ORA-01555: UNDO 보존 시간과 공간 압박을 확인하는 순서

최신 글

  • PostgreSQL 16~18 락 대기 진단: pg_locks·pg_stat_activity로 차단 세션 찾는 순서
  • Oracle 19c 데이터파일 하나 복구: RESTORE·RECOVER 순서와 온라인 전환 기준
  • Oracle 19c RMAN RESTORE VALIDATE: 백업이 실제 복구 가능한지 확인하는 범위와 순서
  • Oracle 19c Flashback Query ORA-01555: UNDO 보존 시간과 공간 압박을 확인하는 순서
  • MySQL 8.4 ONLINE DDL이 LOCK=NONE인데 멈출 때: metadata lock 차단 세션 찾는 순서
  • DB 운영
  • SQL 실무
  • 장애 해결

최신 댓글

보여줄 댓글이 없습니다.
© 2026 KhoonLabs DB – 데이터베이스 기술과 실전 운영 • 제작됨 GeneratePress