잠금 대기, InnoDB deadlock, 느린 SQL을 performance_schema와 정규화된 digest로 구분하고 민감한 SQL 노출과 무분별한 세션 종료 없이 조치합니다.
MySQL lock wait timeoutDeadlock found when trying to get lockSHOW ENGINE INNODB STATUSperformance_schema data_lock_waitsMySQL slow queryevents_statements_summary_by_digest
thread owner, 실행 업무, transaction 변경 행 수와 자동 재시도 여부를 확인하지 못했다면 KILL QUERY·CONNECTION을 실행하지 않습니다.
SHOW ENGINE INNODB STATUS나 SQL digest에 개인정보·비밀·내부 스키마가 포함되면 외부 공유를 중단하고 최소 범위로 마스킹합니다.
복제 지연·백업·DDL·결제·정산 transaction과 연관됐거나 failover 중이면 DB 운영 책임자 승인 전 변경을 멈춥니다.
ROLLBACK
복구 기준
KILL QUERY·CONNECTION은 실행 전 상태로 되돌릴 수 없습니다. 애플리케이션 connection 재수립과 안전한 transaction 재시도, InnoDB rollback 진행을 확인합니다. index·SQL·설정 변경은 별도 migration의 down 절차와 실행 계획·성능 기준으로 복원하고, 데이터 변경 transaction은 백업과 업무 보정 절차를 사용합니다.
ESCALATION PACK
담당자에게 전달할 자료
민감정보를 제거한 data_lock_waits·innodb_trx·metadata_locks 관계와 장애 시각
LATEST DETECTED DEADLOCK의 잠금 순서 요약, Innodb_deadlocks·row lock 지표 변화
정규화된 digest·EXPLAIN 결과, 변경 전후 Threads_running·오류율·복제 지연과 배포 revision
2026년 9월 2일 기준 upstream 공식 문서와 현재 지원 버전을 대조했습니다. 먼저 읽기 전용 명령으로 사실을 확인하고, 변경 명령은 영향·백업·복구 경로를 확인한 뒤 승인된 대상에만 적용하세요. <...> 자리표시자는 승인된 리터럴 값으로 직접 치환하고 외부 입력으로 shell 명령을 조립하거나 eval하지 마세요.
BEFORE YOU START
이런 증상에서 시작합니다
Lock wait timeout exceeded; try restarting transaction 발생
Deadlock found when trying to get lock 오류가 반복됨
Threads_running 증가와 응답 지연·connection pool 고갈 발생
특정 SQL의 평균 지연·rows examined가 지속적으로 증가함
CHECK THE BRANCH
놓치기 쉬운 원인 분기
01
현재 lock wait가 계속 유지되는 경우
data_lock_waits의 요청·차단 transaction을 확인하고 열린 시간과 소유 애플리케이션을 찾습니다. blocker PID만 보고 즉시 KILL하면 미완료 transaction rollback과 서비스 오류가 커질 수 있습니다.
02
Deadlock 오류가 간헐적으로 발생하는 경우
InnoDB는 보통 victim transaction 하나를 자동 rollback합니다. 애플리케이션의 제한된 재시도와 동일한 테이블·행 접근 순서, 짧은 transaction, 적절한 index가 핵심입니다.
03
lock은 없고 느린 SQL이 누적되는 경우
performance_schema digest의 count, total·average latency, rows examined를 보고 후보를 좁힙니다. 단일 순간의 SHOW PROCESSLIST나 전체 일반 로그 활성화만으로 판단하지 않습니다.
04
metadata lock 또는 DDL 대기인 경우
테이블 변경은 열린 transaction과 충돌할 수 있습니다. DDL 재실행 전에 performance_schema.metadata_locks와 배포 이력을 확인하고 점검 시간·온라인 변경 전략을 별도로 세웁니다.
FOLLOW THE FLOW
순서대로 확인하기
1
조회시스템을 변경하지 않는 확인 단계
1분 점검: 서버 상태·대기·활성 세션 요약
mysql --login-path=<OPS_LOGIN_PATH>는 mysql_config_editor로 사전 구성한 최소 조회 계정을 뜻합니다. 비밀번호를 -pPASSWORD 인자로 넣지 않습니다.
버전·읽기 전용·격리 수준
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT VERSION(), @@read_only, @@transaction_isolation;"
활성 thread 지표
mysql --login-path=<OPS_LOGIN_PATH> -e "SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected','Threads_running','Slow_queries');"
SQL 본문 없는 foreground 세션
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT PROCESSLIST_ID,PROCESSLIST_USER,PROCESSLIST_HOST,PROCESSLIST_DB,PROCESSLIST_COMMAND,PROCESSLIST_TIME,PROCESSLIST_STATE FROM performance_schema.threads WHERE TYPE='FOREGROUND' ORDER BY PROCESSLIST_TIME DESC LIMIT 30;"
현재 transaction 대기 수
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT COUNT(*) AS lock_waits FROM performance_schema.data_lock_waits;"
결과 읽기
lock_waits가 있으면 잠금 분기, 없지만 Threads_running·Slow_queries가 높으면 slow query/CPU·I/O 분기입니다. read_only 서버인지도 변경 전에 확인합니다.
다음 판단
장애 시작 시각과 애플리케이션 배포·배치 시각을 맞춰 보고 상세 대기 관계로 이동합니다.
2
조회시스템을 변경하지 않는 확인 단계
요청·차단 transaction 관계 확인
transaction ID와 thread ID, 시작 시각을 확인하되 원문 SQL·바인드 값은 기본 출력하지 않습니다.
data lock wait 관계
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT REQUESTING_ENGINE_TRANSACTION_ID,BLOCKING_ENGINE_TRANSACTION_ID,REQUESTING_ENGINE_LOCK_ID,BLOCKING_ENGINE_LOCK_ID FROM performance_schema.data_lock_waits;"
InnoDB transaction 요약
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT trx_id,trx_state,trx_started,trx_wait_started,trx_mysql_thread_id,trx_rows_locked,trx_rows_modified FROM information_schema.innodb_trx ORDER BY trx_started;"
metadata lock 대기
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT OBJECT_TYPE,OBJECT_SCHEMA,OBJECT_NAME,LOCK_TYPE,LOCK_DURATION,LOCK_STATUS,OWNER_THREAD_ID FROM performance_schema.metadata_locks WHERE LOCK_STATUS='PENDING';"
결과 읽기
오래 열린 transaction이 많은 행을 수정하며 다른 transaction을 막는지, DDL metadata lock인지 구분합니다. blocker가 백업·마이그레이션·정산 작업일 수도 있습니다.
다음 판단
thread owner와 업무 영향, 자동 rollback 비용을 애플리케이션·DB 담당자와 확인합니다.
3
주의서버 부하나 권한을 고려할 단계
최근 deadlock과 재시도 패턴 확인
SHOW ENGINE INNODB STATUS에는 SQL·테이블·호스트 정보가 포함될 수 있으므로 제한된 화면에서 확인하고 공유 전 마스킹합니다.
최근 InnoDB deadlock
mysql --login-path=<OPS_LOGIN_PATH> -e "SHOW ENGINE INNODB STATUS\G"
LATEST DETECTED DEADLOCK 구간만 필요한 범위로 수집하고 리터럴·사용자·호스트·테이블 식별자는 마스킹합니다.
deadlock·lock timeout 누적
mysql --login-path=<OPS_LOGIN_PATH> -e "SHOW GLOBAL STATUS WHERE Variable_name IN ('Innodb_deadlocks','Innodb_row_lock_current_waits','Innodb_row_lock_time','Innodb_row_lock_waits');"
InnoDB 설정 확인
mysql --login-path=<OPS_LOGIN_PATH> -e "SHOW VARIABLES WHERE Variable_name IN ('innodb_deadlock_detect','innodb_lock_wait_timeout','transaction_isolation');"
결과 읽기
LATEST DETECTED DEADLOCK의 두 transaction이 테이블·행을 반대 순서로 잠그는지 봅니다. 한 번의 deadlock은 정상적인 동시성 결과일 수 있지만 반복되면 코드·index·재시도 설계를 바꿔야 합니다.
다음 판단
deadlock detection·timeout 값을 즉흥적으로 바꾸지 말고 transaction 경계와 접근 순서를 우선 수정안으로 잡습니다.
4
조회시스템을 변경하지 않는 확인 단계
정규화 digest로 느린 SQL 후보 확인
리터럴이 제거된 performance_schema digest로 누적 부하를 비교하고 후보 SELECT의 실행 계획을 읽습니다.
평균 지연 상위 digest
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT SCHEMA_NAME,DIGEST_TEXT,COUNT_STAR,ROUND(SUM_TIMER_WAIT/1000000000000,3) AS total_s,ROUND(AVG_TIMER_WAIT/1000000000,3) AS avg_ms,SUM_ROWS_EXAMINED,SUM_ROWS_SENT FROM performance_schema.events_statements_summary_by_digest WHERE DIGEST_TEXT IS NOT NULL ORDER BY SUM_TIMER_WAIT DESC LIMIT 20;"
DIGEST_TEXT는 리터럴을 정규화하지만 스키마·테이블 구조가 드러날 수 있어 외부 공유 전 마스킹합니다.
slow query 설정
mysql --login-path=<OPS_LOGIN_PATH> -e "SHOW VARIABLES WHERE Variable_name IN ('slow_query_log','slow_query_log_file','long_query_time','min_examined_row_limit','log_output');"
검토된 SELECT 실행 계획
mysql --login-path=<OPS_LOGIN_PATH> -e "EXPLAIN FORMAT=TREE <REVIEWED_SELECT_WITHOUT_LITERALS>;"
INSERT·UPDATE·DELETE나 민감한 리터럴을 넣지 않습니다. EXPLAIN ANALYZE는 실제로 쿼리를 실행하므로 이 진단 명령에서는 사용하지 않습니다.
결과 읽기
COUNT_STAR·total_s가 큰 빈번한 SQL과 avg_ms·rows examined가 큰 개별 SQL을 구분합니다. index가 있어도 낮은 선택도·잘못된 join 순서·lock 대기 때문에 느릴 수 있습니다.
이 단계는 실행 중 요청이나 connection을 중단할 수 있습니다. thread owner, transaction 규모, 자동 재시도, 복제·업무 영향을 확인하고 아래 분기 중 승인된 하나만 실행합니다.
변경 단계입니다. 실행 전 대상 이름과 경로, 서비스 중단 영향, 복구 방법을 다시 확인하세요.
대상 thread 재확인
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT PROCESSLIST_ID,PROCESSLIST_USER,PROCESSLIST_HOST,PROCESSLIST_DB,PROCESSLIST_COMMAND,PROCESSLIST_TIME,PROCESSLIST_STATE FROM performance_schema.threads WHERE PROCESSLIST_ID=<APPROVED_THREAD_ID>;"
A. 승인된 실행문만 중단
mysql --login-path=<DBA_LOGIN_PATH> -e "KILL QUERY <APPROVED_THREAD_ID>;"
현재 statement만 오류로 끝나고 연결과 열린 transaction은 유지됩니다. 이전 statement가 잡은 lock은 COMMIT·ROLLBACK·연결 종료까지 남을 수 있으므로 애플리케이션 재시도와 transaction 상태를 확인한 DB 담당자만 실행합니다.
B. 승인된 연결 종료
mysql --login-path=<DBA_LOGIN_PATH> -e "KILL CONNECTION <APPROVED_THREAD_ID>;"
열린 transaction이 rollback되고 connection pool이 오류를 받을 수 있습니다. QUERY 중단으로 부족하고 rollback 비용·업무 영향을 승인받은 경우에만 실행합니다.
대기·지연 재검증
mysql --login-path=<OPS_LOGIN_PATH> -e "SELECT trx_id,trx_state,trx_started,trx_rows_locked,trx_rows_modified FROM information_schema.innodb_trx WHERE trx_mysql_thread_id=<APPROVED_THREAD_ID>; SELECT COUNT(*) AS lock_waits FROM performance_schema.data_lock_waits; SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_running','Innodb_deadlocks','Innodb_row_lock_current_waits','Slow_queries');"
KILL QUERY 뒤 대상 transaction이 남거나 lock wait가 지속되면 잠금이 해제됐다고 판단하지 않습니다. 즉시 KILL CONNECTION으로 확대하지 말고 transaction 소유자와 COMMIT·ROLLBACK·연결 종료 영향을 다시 승인받습니다.
결과 읽기
lock wait와 Threads_running이 줄고 애플리케이션 오류율·복제 지연이 회복돼야 합니다. KILL은 근본 해결이 아니며 rollback이 끝날 때까지 부하가 지속될 수 있습니다.
다음 판단
세션 종료는 되돌릴 수 없으므로 애플리케이션이 connection을 재수립하고 transaction을 안전하게 재시도하는지 확인합니다. 재발 방지는 짧은 transaction, 동일 잠금 순서, 적절한 index, 제한된 deadlock retry, digest·lock wait·slow query 알림을 코드와 운영 기준에 반영합니다.