카테고리 : MySQL/기술노트

InnoDB 상태 진단: SHOW ENGINE INNODB STATUS를 읽는 기본 방법

SHOW ENGINE INNODB STATUS 출력의 구조와 핵심 지표를 InnoDB 운영 진단 관점에서 정리한다.

저자: MySQL 기술 노트 작성: 2026.06.18 약 17분 9,709자
다운로드

1. 왜 SHOW ENGINE INNODB STATUS를 읽어야 하는가

SHOW ENGINE INNODB STATUS는 오래된 명령이지만, InnoDB 장애 진단에서 여전히 중요한 1차 자료다. Performance Schema와 sys schema가 더 구조화된 관측 지점을 제공하더라도, InnoDB 내부 상태를 한 번에 훑어볼 때 이 출력만큼 밀도 높은 진단 화면은 많지 않다. 특히 deadlock, 긴 트랜잭션, purge 지연, buffer pool 압력, semaphore 대기, I/O thread 상태, insert buffer와 adaptive hash index 같은 InnoDB 내부 하위 시스템을 한 문서에서 연결해서 볼 수 있다는 장점이 있다.

운영자가 이 명령을 읽을 수 있어야 하는 이유는 다음과 같다.

  • 애플리케이션에서 “DB가 느리다”는 증상만 보일 때 InnoDB 내부 대기인지, SQL 실행 계획 문제인지, 외부 스토리지 지연인지 1차 분류를 할 수 있다.
  • deadlock 로그를 단순히 에러 메시지로 보지 않고 어떤 인덱스와 레코드에서 충돌했는지 추적할 수 있다.
  • History list length, Log sequence number, Pages made young, Pending reads 같은 지표를 서로 연결해 현재 부하의 성격을 해석할 수 있다.
  • MySQL Community, Percona Server, Aurora MySQL처럼 구현과 관측 도구가 조금씩 다른 환경에서도 InnoDB의 공통 진단 언어를 유지할 수 있다.

다만 이 명령은 “한 번 실행하면 정답을 알려 주는 보고서”가 아니다. 출력은 순간 스냅샷이며, 항목마다 갱신 주기와 의미가 다르다. 일부 값은 누적 카운터이고, 일부 값은 최근 이벤트이며, 일부 값은 현재 큐 길이다. 따라서 올바른 읽기 순서는 섹션 구조를 먼저 파악하고, 현재 장애 가설에 맞는 부분을 좁혀 읽는 것이다.

2. 명령의 성격: 구조화된 테이블이 아니라 InnoDB 내부 스냅샷

가장 기본적인 실행 형식은 다음과 같다. 실제 운영 환경에서는 출력이 매우 길 수 있으므로, 터미널에서는 \G 형태로 세로 출력하는 것이 읽기 쉽다.

mysql> SHOW ENGINE INNODB STATUS\G

이 글에서는 위 명령의 전체 원문을 그대로 싣지 않는다. 환경마다 트랜잭션, 테이블명, SQL 원문, 스레드 ID, 파일 경로가 달라지고, 경우에 따라 민감한 애플리케이션 SQL이 포함될 수 있기 때문이다. 대신 MySQL 8.0에서 검증 가능한 주변 진단 쿼리와 함께, SHOW ENGINE INNODB STATUS 출력의 주요 섹션을 해석하는 방법을 설명한다.

먼저 현재 서버에서 InnoDB가 사용 가능한 상태인지와 기본 잠금 대기 카운터를 확인할 수 있다.

SELECT VERSION() AS mysql_version;
SELECT ENGINE, SUPPORT, COMMENT
FROM information_schema.ENGINES
WHERE ENGINE = 'InnoDB';
SHOW GLOBAL STATUS LIKE 'Innodb_row_lock%';

실행 결과(MySQL 8.0.46):

mysql> SELECT VERSION() AS mysql_version;

+---------------+
| mysql_version |
+---------------+
| 8.0.46        |
+---------------+
1 row in set (0.00 sec)

mysql> SELECT ENGINE, SUPPORT, COMMENT
    -> FROM information_schema.ENGINES
    -> WHERE ENGINE = 'InnoDB';

+--------+---------+------------------------------------------------------------+
| ENGINE | SUPPORT | COMMENT                                                    |
+--------+---------+------------------------------------------------------------+
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys |
+--------+---------+------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SHOW GLOBAL STATUS LIKE 'Innodb_row_lock%';

+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0     |
| Innodb_row_lock_time          | 0     |
| Innodb_row_lock_time_avg      | 0     |
| Innodb_row_lock_time_max      | 0     |
| Innodb_row_lock_waits         | 0     |
+-------------------------------+-------+
5 rows in set (0.00 sec)

SHOW ENGINE INNODB STATUS는 내부적으로 InnoDB Monitor 출력에 가깝다. 즉, SQL 표준 결과라기보다 InnoDB 엔진이 자기 상태를 텍스트로 덤프한 것이다. 그래서 다음과 같은 특징을 가진다.

특징 운영상 의미
긴 텍스트 출력 자동 파싱보다 사람이 먼저 섹션 단위로 해석하는 데 적합하다.
일부 민감 정보 포함 가능 실행 중인 SQL, 테이블명, 인덱스명, 트랜잭션 정보가 노출될 수 있다.
순간 스냅샷 한 번의 출력만으로 추세를 판단하지 말고 짧은 간격으로 반복 관찰한다.
버전별 차이 존재 MySQL 8.0 minor version, 빌드, 설정에 따라 항목과 표현이 달라질 수 있다.
Performance Schema와 보완 관계 구조화된 분석은 Performance Schema, 빠른 전체 조망은 InnoDB status가 유용하다.

Aurora MySQL에서도 InnoDB status는 유용하지만, 스토리지 계층이 Aurora 분산 스토리지로 분리되어 있기 때문에 파일 I/O, redo 내구성, crash recovery 관련 해석은 Community MySQL과 동일하게 단정하면 안 된다. Aurora에서는 CloudWatch, Performance Insights, Enhanced Monitoring, wait event까지 함께 봐야 한다.

3. 전체 구조: 어느 섹션을 먼저 볼 것인가

전형적인 출력은 다음과 같은 섹션을 포함한다. 버전과 상태에 따라 일부 항목은 생략되거나 표현이 달라질 수 있다.

flowchart TD
  A[SHOW ENGINE INNODB STATUS] --> B[BACKGROUND THREAD]
  A --> C[SEMAPHORES]
  A --> D[LATEST DETECTED DEADLOCK]
  A --> E[TRANSACTIONS]
  A --> F[FILE I/O]
  A --> G[INSERT BUFFER AND ADAPTIVE HASH INDEX]
  A --> H[LOG]
  A --> I[BUFFER POOL AND MEMORY]
  A --> J[ROW OPERATIONS]

  C --> C1[mutex/rw-lock 대기]
  D --> D1[최근 deadlock 원인]
  E --> E1[활성 트랜잭션과 undo/purge 영향]
  H --> H1[redo LSN/checkpoint 압력]
  I --> I1[buffer pool hit/read/flush 상태]

장애 상황에서 읽는 우선순위는 증상에 따라 달라진다.

증상 먼저 볼 섹션 함께 볼 지표
애플리케이션 timeout, row lock wait 증가 TRANSACTIONS, LATEST DETECTED DEADLOCK performance_schema.data_lock_waits, Innodb_row_lock%
CPU 사용률이 높고 SQL 처리량 저하 SEMAPHORES, ROW OPERATIONS Performance Schema wait, statement digest
쓰기 지연, checkpoint 압력 LOG, BUFFER POOL AND MEMORY, FILE I/O redo LSN 차이, dirty page, fsync 지연
purge 지연, undo tablespace 증가 TRANSACTIONS History list length, long transaction
읽기 성능 저하, 디스크 read 증가 BUFFER POOL AND MEMORY buffer pool hit, pending reads, pages made young

중요한 점은 한 섹션만 보고 결론을 내리지 않는 것이다. 예를 들어 History list length가 크다고 해서 항상 purge thread 자체가 문제라는 뜻은 아니다. 장시간 열린 read transaction 때문에 purge가 진행할 수 없는 상황일 수 있고, 대량 DML 직후 자연스럽게 정리 중인 상태일 수도 있다. 마찬가지로 Pending reads가 보인다고 해서 즉시 스토리지 장애라고 단정할 수 없다. buffer pool warm-up이 끝나지 않았거나, 실행 계획 변화로 working set이 커졌을 수 있다.

4. SEMAPHORES: 내부 latch 경합을 보는 창

SEMAPHORES 섹션은 InnoDB 내부 mutex와 rw-lock 대기를 보여준다. 행 잠금(row lock)과 혼동하면 안 된다. row lock은 트랜잭션 간 데이터 레코드 접근 충돌이고, semaphore는 InnoDB 내부 자료구조를 보호하기 위한 latch 경합에 가깝다.

운영에서 이 섹션을 볼 때는 다음 질문을 던진다.

  1. 특정 mutex 또는 rw-lock 대기가 반복적으로 많이 보이는가?
  2. 대기 시간이 길고, 같은 코드 경로가 계속 등장하는가?
  3. 동시에 CPU 사용률, context switch, thread 수가 비정상적으로 증가했는가?
  4. MySQL 버전에서 알려진 InnoDB 경합 문제가 있는가?

일시적인 semaphore 대기는 정상이다. InnoDB는 buffer pool, lock system, transaction system, adaptive hash index 등 공유 자료구조를 다루므로 내부 latch가 반드시 필요하다. 문제는 대기가 짧게 나타나는 것이 아니라, 특정 latch가 병목이 되어 전체 처리량을 제한하는 경우다.

MySQL 8.0에서는 SHOW ENGINE INNODB STATUS만으로 semaphore 문제를 결론 내리기보다 Performance Schema wait summary와 함께 본다. 다음 쿼리는 현재 서버에서 InnoDB 관련 wait instrument가 노출되는지 확인하는 출발점으로 사용할 수 있다.

SELECT NAME, ENABLED, TIMED
FROM performance_schema.setup_instruments
WHERE NAME LIKE 'wait/synch/%/innodb/%'
ORDER BY NAME
LIMIT 10;

실행 결과(MySQL 8.0.46):

mysql> SELECT NAME, ENABLED, TIMED
    -> FROM performance_schema.setup_instruments
    -> WHERE NAME LIKE 'wait/synch/%/innodb/%'
    -> ORDER BY NAME
    -> LIMIT 10;

+----------------------------------------------------+---------+-------+
| NAME                                               | ENABLED | TIMED |
+----------------------------------------------------+---------+-------+
| wait/synch/cond/innodb/commit_cond                 | NO      | NO    |
| wait/synch/cond/innodb/resume_encryption_cond      | NO      | NO    |
| wait/synch/mutex/innodb/ahi_enabled_mutex          | NO      | NO    |
| wait/synch/mutex/innodb/alter_stage_mutex          | NO      | NO    |
| wait/synch/mutex/innodb/autoinc_mutex              | NO      | NO    |
| wait/synch/mutex/innodb/autoinc_persisted_mutex    | NO      | NO    |
| wait/synch/mutex/innodb/buf_pool_chunks_mutex      | NO      | NO    |
| wait/synch/mutex/innodb/buf_pool_flush_state_mutex | NO      | NO    |
| wait/synch/mutex/innodb/buf_pool_free_list_mutex   | NO      | NO    |
| wait/synch/mutex/innodb/buf_pool_LRU_list_mutex    | NO      | NO    |
+----------------------------------------------------+---------+-------+
10 rows in set (0.00 sec)

이 결과가 비어 있거나 ENABLEDNO라면, 해당 서버의 Performance Schema 설정에서 세부 wait 계측이 제한되어 있을 수 있다. 반대로 instrument가 켜져 있다면 events_waits_summary_global_by_event_name 같은 요약 테이블로 어떤 내부 wait가 누적되는지 추가 분석할 수 있다.

5. LATEST DETECTED DEADLOCK: 최근 deadlock은 “대표 사례”일 뿐이다

LATEST DETECTED DEADLOCK 섹션은 가장 최근에 InnoDB deadlock detector가 감지한 deadlock의 상세 내용을 보여준다. 여기에는 두 개 이상의 트랜잭션, 각 트랜잭션이 보유하거나 기다린 lock, 관련 SQL, 인덱스와 레코드 정보가 포함된다.

이 섹션을 읽을 때 흔한 오해가 있다. 출력에 나온 deadlock 하나가 전체 장애의 유일한 원인이라고 보는 것이다. 실제로는 다음과 같이 해석해야 한다.

  • 이 섹션은 “마지막 deadlock 사례”이지, 전체 deadlock 통계가 아니다.
  • deadlock은 InnoDB가 피해 트랜잭션 하나를 rollback하여 해결한 충돌이다. 따라서 지속적인 lock wait와는 성격이 다르다.
  • 같은 패턴이 반복되는지 확인하려면 애플리케이션 로그, MySQL error log의 deadlock 출력 설정, Performance Schema, slow query log를 함께 봐야 한다.
  • deadlock 자체보다 deadlock을 유발한 접근 순서, 인덱스 부재, 트랜잭션 범위, 배치 처리 순서가 더 중요한 개선 대상이다.

Deadlock 분석의 기본 순서는 다음과 같다.

  1. TRANSACTION 블록에서 각 트랜잭션의 SQL과 상태를 확인한다.
  2. WAITING FOR THIS LOCK TO BE GRANTEDHOLDS THE LOCK(S)를 비교한다.
  3. 충돌한 인덱스가 의도한 인덱스인지 확인한다.
  4. WHERE 조건이 충분히 selective한지, 불필요하게 넓은 범위를 잠그는지 본다.
  5. 두 트랜잭션이 같은 객체를 다른 순서로 접근하는지 확인한다.
  6. 애플리케이션 재시도 로직이 deadlock을 정상적으로 처리하는지 확인한다.

운영 환경에서 deadlock 원문을 저장해야 한다면 innodb_print_all_deadlocks 설정을 검토할 수 있다. 단, 모든 deadlock을 error log에 남기면 로그량과 민감정보 노출이 증가할 수 있다.

SHOW VARIABLES LIKE 'innodb_print_all_deadlocks';
SHOW VARIABLES LIKE 'innodb_status_output%';

실행 결과(MySQL 8.0.46):

mysql> SHOW VARIABLES LIKE 'innodb_print_all_deadlocks';

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_print_all_deadlocks | OFF   |
+----------------------------+-------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'innodb_status_output%';

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_status_output       | OFF   |
| innodb_status_output_locks | OFF   |
+----------------------------+-------+
2 rows in set (0.00 sec)

innodb_status_outputinnodb_status_output_locks는 InnoDB Monitor 출력을 error log에 주기적으로 남기는 설정이다. 장애 순간의 상태를 놓치지 않는 데 도움이 될 수 있지만, 운영 환경에서 장기간 켜 두면 로그량이 커지고 SQL/스키마 정보가 노출될 수 있으므로 제한된 기간에만 사용하는 것이 안전하다.

6. TRANSACTIONS: 긴 트랜잭션, purge 지연, lock wait를 연결해서 본다

TRANSACTIONS 섹션은 InnoDB 상태 진단에서 가장 자주 보는 부분이다. 여기에는 transaction id counter, purge 상태, history list length, 현재 활성 트랜잭션 목록, lock wait 정보가 포함될 수 있다.

특히 다음 항목을 주의해서 본다.

항목 의미 운영 해석
Trx id counter 새 트랜잭션 ID 증가 흐름 쓰기 부하와 트랜잭션 활동성을 간접적으로 보여준다.
Purge done for trx's n:o purge가 어디까지 진행했는지 오래 밀리면 undo 이력이 쌓일 수 있다.
History list length purge 대상 undo 이력 길이 긴 read transaction, 대량 DML, purge 지연의 신호일 수 있다.
LIST OF TRANSACTIONS 현재 트랜잭션 목록 장시간 열린 트랜잭션과 lock wait를 찾는다.
lock struct(s) / row lock(s) 보유 lock 규모 비정상적으로 넓은 범위 잠금 여부를 추정한다.

여기서 중요한 기준은 “값이 크면 무조건 장애”가 아니라 “시간에 따라 줄어드는지, 같은 원인이 반복되는지”다. 예를 들어 대량 DELETE 직후 History list length가 증가했다가 점차 감소한다면 purge가 부채를 갚고 있는 과정일 수 있다. 반대로 수십 분 이상 계속 증가하고, 오래 열린 read-only transaction이 보인다면 purge가 진행할 수 없는 상태일 수 있다.

Lock wait는 가능하면 Performance Schema의 구조화된 테이블로도 확인한다. 다음 쿼리는 MySQL 8.0에서 performance_schema.data_lock_waits 객체가 존재하는지와 현재 대기 행 수를 확인하는 가벼운 예시다.

SHOW TABLES FROM performance_schema LIKE 'data_lock_waits';
SELECT COUNT(*) AS current_lock_waits
FROM performance_schema.data_lock_waits;

실행 결과(MySQL 8.0.46):

mysql> SHOW TABLES FROM performance_schema LIKE 'data_lock_waits';

+------------------------------------------------+
| Tables_in_performance_schema (data_lock_waits) |
+------------------------------------------------+
| data_lock_waits                                |
+------------------------------------------------+
1 row in set (0.01 sec)

mysql> SELECT COUNT(*) AS current_lock_waits
    -> FROM performance_schema.data_lock_waits;

+--------------------+
| current_lock_waits |
+--------------------+
|                  0 |
+--------------------+
1 row in set (0.00 sec)

실제 대기 관계를 상세히 보려면 performance_schema.data_locks, data_lock_waits, threads, events_statements_current를 조인해서 blocking/waiting thread를 확인한다. 다만 이 글의 주제는 SHOW ENGINE INNODB STATUS의 기본 독해법이므로, 구조화된 lock wait 분석은 별도 글에서 더 깊게 다루는 것이 적절하다.

Aurora MySQL에서는 장시간 트랜잭션이 복제 지연, purge, undo 보존, 스토리지 사용량, Performance Insights wait event와 함께 나타날 수 있다. 특히 writer에서 긴 트랜잭션이 열린 상태로 배치가 누적되면 reader endpoint에서 보이는 지연 증상과 연결될 수 있으므로, InnoDB status와 Aurora 관측 지표를 분리해서 보지 말아야 한다.

7. FILE I/O와 LOG: 느린 디스크인지, checkpoint 압력인지 구분한다

FILE I/O 섹션은 InnoDB I/O thread 상태와 pending I/O를 보여준다. LOG 섹션은 redo log의 LSN, flushed up to, checkpoint 위치를 보여준다. 이 둘은 쓰기 부하와 crash recovery 위험을 해석할 때 함께 읽어야 한다.

운영자가 자주 보는 질문은 다음과 같다.

  • pending normal aio reads/writes가 계속 쌓이는가?
  • pending flushes가 증가하는가?
  • Log sequence numberLast checkpoint at의 차이가 계속 커지는가?
  • dirty page 비율이 높고 page cleaner가 따라가지 못하는가?
  • 쓰기 지연이 특정 시간대 배치, purge, checkpoint, redo fsync와 맞물리는가?

SHOW ENGINE INNODB STATUS의 LSN 값은 한 번만 보면 의미가 제한적이다. 같은 명령을 짧은 간격으로 반복해 LSN 증가 속도와 checkpoint 전진 속도를 비교해야 한다. checkpoint가 뒤처지면 crash recovery 시 다시 적용해야 할 redo 범위가 커질 수 있고, buffer pool flush 압력이 증가할 수 있다.

MySQL 8.0에서는 일부 redo 관련 상태가 status variable로도 제공된다. 다음 쿼리는 서버에서 노출되는 InnoDB redo 관련 상태 변수를 확인하는 예시다. 변수 집합은 minor version에 따라 달라질 수 있으므로, 결과가 적거나 비어 있어도 그 자체가 장애를 뜻하지는 않는다.

SHOW GLOBAL STATUS LIKE 'Innodb_redo_log%';
SHOW GLOBAL STATUS LIKE 'Innodb_os_log%';

실행 결과(MySQL 8.0.46):

mysql> SHOW GLOBAL STATUS LIKE 'Innodb_redo_log%';

+-------------------------------------+------------+
| Variable_name                       | Value      |
+-------------------------------------+------------+
| Innodb_redo_log_read_only           | OFF        |
| Innodb_redo_log_uuid                | 1017559209 |
| Innodb_redo_log_checkpoint_lsn      | 29620108   |
| Innodb_redo_log_current_lsn         | 29620108   |
| Innodb_redo_log_flushed_to_disk_lsn | 29620108   |
| Innodb_redo_log_logical_size        | 512        |
| Innodb_redo_log_physical_size       | 3276800    |
| Innodb_redo_log_capacity_resized    | 104857600  |
| Innodb_redo_log_resize_status       | OK         |
| Innodb_redo_log_enabled             | ON         |
+-------------------------------------+------------+
10 rows in set (0.00 sec)

mysql> SHOW GLOBAL STATUS LIKE 'Innodb_os_log%';

+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| Innodb_os_log_fsyncs         | 20    |
| Innodb_os_log_pending_fsyncs | 0     |
| Innodb_os_log_pending_writes | 0     |
| Innodb_os_log_written        | 82944 |
+------------------------------+-------+
4 rows in set (0.00 sec)

Aurora MySQL에서는 redo와 스토리지 내구성 경로가 Community MySQL의 로컬 파일 시스템 모델과 다르다. 따라서 FILE I/O 섹션의 파일 대기만으로 Aurora 스토리지 상태를 결론 내리면 안 된다. Aurora에서는 VolumeWriteIOPs, CommitLatency, DB load, wait event, redo 관련 엔진 지표를 함께 확인해야 한다.

8. BUFFER POOL AND MEMORY: 캐시 효율보다 “압력의 방향”을 본다

BUFFER POOL AND MEMORY 섹션은 buffer pool 크기, free buffer, database pages, old database pages, modified db pages, pending reads/writes, page young/non-young 통계를 보여준다. 흔히 buffer pool hit ratio만 보려 하지만, 실제 운영에서는 다음 방향성이 더 중요하다.

관찰 지점 해석 질문
Free buffers가 거의 없고 pending read가 증가 working set이 buffer pool보다 큰가? 실행 계획 변화로 읽기 범위가 커졌는가?
Modified db pages가 높고 flush가 따라가지 못함 쓰기 부하, checkpoint, storage latency가 병목인가?
Pages made young/non-young 변화 LRU에서 hot page와 scan성 읽기가 어떻게 섞이는가?
Buffer pool hit rate 저하 실제 디스크 read 증가와 연결되는가, 재시작 직후 warm-up인가?

Buffer pool 관련 값은 순간값과 누적값이 섞여 있다. 예를 들어 hit rate는 장기간 누적 통계의 영향을 받을 수 있고, pending read는 순간 큐 길이에 가깝다. 따라서 장애 분석에서는 “지금 쌓여 있는 것”과 “지금까지 누적된 것”을 구분해야 한다.

운영에서 buffer pool 문제를 의심할 때는 InnoDB status와 함께 다음 항목을 확인한다.

  • 상위 SQL digest의 logical read, rows examined, execution count
  • 실행 계획 변화와 새 인덱스/통계 변경 여부
  • buffer pool 크기와 인스턴스 메모리 여유
  • read IOPS와 read latency
  • 재시작, failover, 배포 직후 warm-up 여부

Aurora reader에서 갑자기 읽기 지연이 커졌다면, writer와 reader의 buffer cache 상태가 다를 수 있다. Aurora의 분산 스토리지는 데이터를 공유하지만 각 DB 인스턴스의 buffer pool은 독립적이다. 따라서 failover 직후 새 writer가 cold cache에 가까운 상태라면 InnoDB status의 buffer pool 지표와 CloudWatch read latency를 함께 보는 것이 중요하다.

9. ROW OPERATIONS: 스레드 활동과 처리 방향을 확인한다

ROW OPERATIONS 섹션은 InnoDB main thread 상태, read/write/insert/update/delete row operation rate, queries inside InnoDB, queued queries 등을 보여준다. 이 섹션은 단독으로 원인을 확정하기보다, 서버가 현재 어떤 방향의 일을 하고 있는지 확인하는 데 유용하다.

예를 들어 다음과 같은 해석이 가능하다.

  • queries inside InnoDB가 많고 lock wait도 증가하면 트랜잭션 경합 가능성을 본다.
  • row reads가 급증하고 buffer pool read도 증가하면 비효율적인 scan 또는 working set 증가를 의심한다.
  • updates/deletes가 많고 history list length가 증가하면 undo/purge 압력을 함께 본다.
  • main thread 상태가 flushing, sleeping, purging 같은 방향으로 반복되는지 확인한다.

단, row operation rate는 서버 전체 처리량을 대략적으로 보여줄 뿐이다. 어떤 SQL이 원인인지는 Performance Schema statement digest, slow query log, application trace와 연결해야 한다.

10. 안전한 운영 절차: 한 번 실행하고 끝내지 않는다

SHOW ENGINE INNODB STATUS를 운영에서 사용할 때는 다음 절차가 안전하다.

  1. 장애 시각, 애플리케이션 증상, 영향 범위를 먼저 기록한다.
  2. SHOW ENGINE INNODB STATUS\G를 즉시 1회 수집한다.
  3. 10~30초 간격으로 2~3회 더 수집해 값이 증가하는지, 줄어드는지 본다.
  4. TRANSACTIONS, SEMAPHORES, LOG, BUFFER POOL 중 증상과 맞는 섹션을 먼저 좁힌다.
  5. Performance Schema, slow query log, error log, OS 지표, 클라우드 지표와 대조한다.
  6. 출력에 포함된 SQL, 테이블명, 사용자 정보가 외부로 노출되지 않도록 공유 범위를 통제한다.

다음은 운영자가 수집 전후에 함께 확인하기 좋은, 비교적 안전한 보조 쿼리다.

SHOW GLOBAL STATUS LIKE 'Threads_running';
SHOW GLOBAL STATUS LIKE 'Questions';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';
SHOW GLOBAL STATUS LIKE 'Innodb_data_pending%';

실행 결과(MySQL 8.0.46):

mysql> SHOW GLOBAL STATUS LIKE 'Threads_running';

+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| Threads_running | 2     |
+-----------------+-------+
1 row in set (0.00 sec)

mysql> SHOW GLOBAL STATUS LIKE 'Questions';

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions     | 38    |
+---------------+-------+
1 row in set (0.00 sec)

mysql> SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';

+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| Innodb_buffer_pool_reads | 1021  |
+--------------------------+-------+
1 row in set (0.00 sec)

mysql> SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';

+----------------------------------+-------+
| Variable_name                    | Value |
+----------------------------------+-------+
| Innodb_buffer_pool_read_requests | 16066 |
+----------------------------------+-------+
1 row in set (0.00 sec)

mysql> SHOW GLOBAL STATUS LIKE 'Innodb_data_pending%';

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Innodb_data_pending_fsyncs | 0     |
| Innodb_data_pending_reads  | 0     |
| Innodb_data_pending_writes | 0     |
+----------------------------+-------+
3 rows in set (0.00 sec)

이 값들도 한 번만 보면 의미가 제한적이다. Questions, Innodb_buffer_pool_reads, Innodb_buffer_pool_read_requests는 누적 카운터이므로 짧은 간격으로 두 번 이상 수집해 증가량을 비교해야 한다. 반면 Threads_running이나 pending 계열은 순간 상태에 더 가깝다.

11. 흔한 오해와 주의점

11.1 출력이 길수록 문제가 큰 것은 아니다

정상 서버에서도 InnoDB status 출력은 길다. 트랜잭션이 많거나 최근 deadlock이 있으면 더 길어진다. 길이 자체보다 특정 섹션의 값이 반복적으로 악화되는지가 중요하다.

11.2 마지막 deadlock을 장애 원인 전체로 일반화하지 않는다

LATEST DETECTED DEADLOCK은 마지막 사례다. 장애 시간대에 deadlock이 1회 발생했고 실제 timeout 원인은 lock wait 증가일 수도 있다. deadlock과 lock wait는 모두 잠금 문제지만, 해결 방식과 운영 영향이 다르다.

11.3 History list length는 절대 기준값보다 추세가 중요하다

환경마다 정상 범위가 다르다. 대량 배치 직후 일시적으로 증가할 수 있으며, purge가 따라잡으면 정상화된다. 문제는 긴 트랜잭션 때문에 줄지 않거나, 계속 증가하는 경우다.

11.4 InnoDB 내부 latch와 row lock을 혼동하지 않는다

SEMAPHORES는 내부 동기화 대기다. 애플리케이션 트랜잭션 간 레코드 잠금 충돌은 TRANSACTIONS, LATEST DETECTED DEADLOCK, Performance Schema lock 테이블에서 확인한다.

11.5 민감정보를 포함할 수 있다

출력에는 SQL 원문, 테이블명, 인덱스명, 트랜잭션 정보가 포함될 수 있다. 장애 보고서나 외부 티켓에 첨부하기 전에는 SQL literal, 고객 식별자, 내부 스키마명, 계정 정보를 확인해야 한다.

12. 점검표: SHOW ENGINE INNODB STATUS 독해 순서

  • LATEST DETECTED DEADLOCK
  • TRANSACTIONS
  • SEMAPHORES
  • LOG
  • BUFFER POOL AND MEMORY

13. 결론

SHOW ENGINE INNODB STATUS는 InnoDB를 깊게 이해하지 못하면 난해한 텍스트 덤프로 보인다. 그러나 섹션별 목적을 알면 이 명령은 장애 순간의 내부 상태를 빠르게 조망하는 강력한 진단 도구가 된다. 핵심은 전체 출력을 암기하는 것이 아니라, 증상에 따라 TRANSACTIONS, SEMAPHORES, LOG, BUFFER POOL, LATEST DETECTED DEADLOCK을 어떤 순서로 읽을지 정하는 것이다.

앞으로의 잠금, purge, redo, buffer pool, Performance Schema 진단 글에서는 이 출력의 각 섹션을 더 세분화해 다룰 수 있다. 운영자는 오늘의 글을 기준 독해법으로 삼고, 실제 장애 상황에서는 반복 수집과 교차 검증을 통해 InnoDB 내부 상태를 구조적으로 해석해야 한다.