---
title: "SHOW PROCESSLIST와 performance_schema.threads 비교"
description: "MySQL 세션 관측의 두 출발점인 SHOW PROCESSLIST와 performance_schema.threads의 데이터 구조, 활용 범위, 권한, 운영 진단 절차를 비교한다."
tags: [ MySQL, 운영, 성능최적화, DBA ]
image: "mysql-report-bg.png"
published: "2026-08-22"
updated: "2026-08-22"
author: "MySQL 기술 노트"
source_url: ""
---

# SHOW PROCESSLIST와 performance_schema.threads 비교

MySQL 장애 대응에서 가장 먼저 묻는 질문은 대개 “지금 서버에서 무엇이 실행 중인가?”이다. `SHOW PROCESSLIST`는 이 질문에 빠르게 답하는 운영 명령이고, `performance_schema.threads`는 같은 세션을 다른 Performance Schema 관측 자료와 연결하기 위한 관계형 출발점이다. 둘은 경쟁 관계가 아니라 **즉시 확인용 인터페이스와 정밀 분석용 데이터 모델**로 구분하는 편이 정확하다.

이 글은 MySQL 8.0 이상을 기준으로 두 방법이 무엇을 보여 주고, 어디에서 정보가 달라지며, 어떤 상황에 무엇을 선택해야 하는지 설명한다. 단일 명령의 출력만 보고 장기 실행 쿼리나 잠금 원인을 단정하지 않도록 진단 절차와 주의점도 함께 정리한다.

## 1. 같은 세션을 보는 두 개의 창

`SHOW PROCESSLIST`의 결과는 사람에게 바로 읽히도록 정리되어 있다. 연결 ID, 사용자, 접속 위치, 기본 데이터베이스, 명령 종류, 경과 시간, 상태, 실행 SQL을 한 화면에 보여 준다. 반면 `performance_schema.threads`는 서버 내부 thread의 식별자와 연결 속성을 열로 제공한다. SQL로 필터링·정렬·집계할 수 있고 다른 Performance Schema 테이블과 `THREAD_ID`로 조인할 수 있다는 점이 핵심이다.

```mermaid
flowchart LR
    C[클라이언트 연결] --> T[서버 thread]
    T --> S[performance_schema.threads]
    T --> P[SHOW FULL PROCESSLIST]
    S --> E[events_statements_current]
    S --> W[data_lock_waits / data_locks]
    S --> A[SQL 필터·집계·조인]
    P --> Q[즉시 육안 확인]
```

두 식별자를 혼동하지 않아야 한다.

- `SHOW PROCESSLIST.Id`는 클라이언트 연결 ID이다.
- `performance_schema.threads.PROCESSLIST_ID`는 그 연결 ID에 대응한다.
- `performance_schema.threads.THREAD_ID`는 Performance Schema 내부 thread 식별자이며 statement, wait, stage, lock 계열 테이블을 연결할 때 사용한다.
- background thread에는 일반적으로 `PROCESSLIST_ID`가 없지만 `THREAD_ID`는 존재할 수 있다.

따라서 애플리케이션 로그에 남은 `CONNECTION_ID()`를 찾을 때는 `PROCESSLIST_ID`와 비교하고, Performance Schema 내부 자료를 조인할 때는 `THREAD_ID`를 사용한다.

## 2. SHOW PROCESSLIST: 빠른 현장 확인

기본 명령은 다음 두 가지이다.

```sql
SELECT VERSION() AS mysql_version,
       CONNECTION_ID() AS connection_id,
       @@performance_schema AS performance_schema_enabled;

SHOW FULL PROCESSLIST;
```

실행 결과(MySQL 8.0.x):

```text
mysql> SELECT VERSION() AS mysql_version,
    ->        CONNECTION_ID() AS connection_id,
    ->        @@performance_schema AS performance_schema_enabled;

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

mysql> SHOW FULL PROCESSLIST;

+----+-----------------+-----------+-----------------+---------+------+------------------------+-----------------------+
| Id | User            | Host      | db              | Command | Time | State                  | Info                  |
+----+-----------------+-----------+-----------------+---------+------+------------------------+-----------------------+
|  5 | event_scheduler | localhost | NULL            | Daemon  |    6 | Waiting on empty queue | NULL                  |
| 11 | root            | localhost | mysql_tech_note | Query   |    0 | init                   | SHOW FULL PROCESSLIST |
+----+-----------------+-----------+-----------------+---------+------+------------------------+-----------------------+
2 rows in set (0.00 sec)
```

`FULL`이 없으면 `Info` 열의 SQL 텍스트가 제한되어 원인 판단에 필요한 뒷부분이 잘릴 수 있다. 운영 점검에서는 습관적으로 `SHOW FULL PROCESSLIST`를 사용하는 편이 안전하다.

각 열은 다음처럼 해석한다.

| 열 | 의미 | 운영 시 주의점 |
|---|---|---|
| `Id` | 연결 ID | `KILL <Id>`의 대상이므로 오인하면 안 된다. |
| `User`, `Host` | 계정과 접속 위치 | 프록시를 사용하면 실제 애플리케이션 노드와 다를 수 있다. |
| `db` | 현재 기본 스키마 | SQL이 다른 스키마를 완전 수식하면 실제 접근 대상과 다를 수 있다. |
| `Command` | 현재 명령의 큰 분류 | `Sleep`은 실행 중 SQL이 없다는 뜻이지 연결 비용이 없다는 뜻은 아니다. |
| `Time` | 현재 상태를 유지한 시간(초) | 트랜잭션 전체 수명과 같다고 단정할 수 없다. |
| `State` | 실행 단계의 짧은 설명 | 짧은 순간값이며 샘플 사이에서 바뀔 수 있다. |
| `Info` | 현재 SQL 텍스트 | 준비 문장, instrumentation, 권한에 따라 정보가 제한될 수 있다. |

`SHOW FULL PROCESSLIST`가 특히 유용한 상황은 다음과 같다.

1. 장애 직후 5~10초 안에 전체 연결 분포를 빠르게 확인할 때
2. 특정 연결 ID가 살아 있는지 확인할 때
3. `Sleep`, 장기 실행, 특정 `State`가 비정상적으로 몰리는지 육안으로 볼 때
4. 추가 쿼리를 작성할 여유가 없는 초기 대응 단계

그러나 출력은 한 시점의 snapshot이다. 1초 뒤에는 행과 상태가 달라질 수 있으며, 높은 `Time` 값 하나만으로 CPU 병목·잠금 대기·긴 트랜잭션을 구분할 수 없다.

## 3. performance_schema.threads: 관계형 진단의 기준점

`threads` 테이블은 foreground 연결뿐 아니라 MySQL 내부 background thread도 포함할 수 있다. 먼저 대상 서버에서 Performance Schema와 테이블 존재 여부를 확인한다.

```sql
SELECT @@performance_schema AS performance_schema_enabled;

SHOW TABLES FROM performance_schema LIKE 'threads';

SELECT THREAD_ID,
       NAME,
       TYPE,
       PROCESSLIST_ID,
       PROCESSLIST_COMMAND,
       PROCESSLIST_TIME,
       PROCESSLIST_STATE
FROM performance_schema.threads
WHERE PROCESSLIST_ID = CONNECTION_ID();
```

실행 결과(MySQL 8.0.x):

```text
mysql> SELECT @@performance_schema AS performance_schema_enabled;

+----------------------------+
| performance_schema_enabled |
+----------------------------+
|                          1 |
+----------------------------+
1 row in set (0.00 sec)

mysql> SHOW TABLES FROM performance_schema LIKE 'threads';

+----------------------------------------+
| Tables_in_performance_schema (threads) |
+----------------------------------------+
| threads                                |
+----------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT THREAD_ID,
    ->        NAME,
    ->        TYPE,
    ->        PROCESSLIST_ID,
    ->        PROCESSLIST_COMMAND,
    ->        PROCESSLIST_TIME,
    ->        PROCESSLIST_STATE
    -> FROM performance_schema.threads
    -> WHERE PROCESSLIST_ID = CONNECTION_ID();

+-----------+---------------------------+------------+----------------+---------------------+------------------+-------------------+
| THREAD_ID | NAME                      | TYPE       | PROCESSLIST_ID | PROCESSLIST_COMMAND | PROCESSLIST_TIME | PROCESSLIST_STATE |
+-----------+---------------------------+------------+----------------+---------------------+------------------+-------------------+
|        50 | thread/sql/one_connection | FOREGROUND |             12 | Query               |                0 | executing         |
+-----------+---------------------------+------------+----------------+---------------------+------------------+-------------------+
1 row in set (0.00 sec)
```

주요 열의 관계는 다음과 같다.

| `threads` 열 | 용도 |
|---|---|
| `THREAD_ID` | statement, wait, stage, lock 자료와 조인하는 내부 키 |
| `NAME` | thread instrumentation 이름 |
| `TYPE` | `FOREGROUND` 또는 `BACKGROUND` 구분 |
| `PROCESSLIST_ID` | 클라이언트 연결 ID, background thread는 `NULL`일 수 있음 |
| `PROCESSLIST_USER`, `PROCESSLIST_HOST` | 연결 계정과 호스트 |
| `PROCESSLIST_DB` | 현재 기본 스키마 |
| `PROCESSLIST_COMMAND` | processlist 명령 상태 |
| `PROCESSLIST_TIME` | 현재 상태의 경과 시간 |
| `PROCESSLIST_STATE` | 현재 실행 상태 |
| `PROCESSLIST_INFO` | 현재 SQL 텍스트 |
| `PARENT_THREAD_ID` | thread 생성 관계를 추적할 때 사용하는 부모 식별자 |
| `INSTRUMENTED`, `HISTORY` | 해당 thread의 계측·이력 수집 여부 판단에 유용한 플래그 |

`threads`의 장점은 원하는 조건을 명시적으로 쓸 수 있다는 데 있다. 예를 들어 일반 클라이언트 연결(`thread/sql/one_connection`)을 명령별로 집계하면 연결 고갈과 idle connection 누적을 빠르게 구분할 수 있다. `TYPE = 'FOREGROUND'`만 사용하면 Event Scheduler 등 연결이 아닌 foreground thread가 포함될 수 있으므로 목적에 맞게 `NAME`도 확인한다.

```sql
SELECT COALESCE(PROCESSLIST_COMMAND, '<none>') AS command_name,
       COUNT(*) AS thread_count,
       MAX(COALESCE(PROCESSLIST_TIME, 0)) AS max_state_seconds
FROM performance_schema.threads
WHERE TYPE = 'FOREGROUND'
  AND NAME = 'thread/sql/one_connection'
  AND PROCESSLIST_ID IS NOT NULL
GROUP BY PROCESSLIST_COMMAND
ORDER BY thread_count DESC, command_name;
```

실행 결과(MySQL 8.0.x):

```text
mysql> SELECT COALESCE(PROCESSLIST_COMMAND, '<none>') AS command_name,
    ->        COUNT(*) AS thread_count,
    ->        MAX(COALESCE(PROCESSLIST_TIME, 0)) AS max_state_seconds
    -> FROM performance_schema.threads
    -> WHERE TYPE = 'FOREGROUND'
    ->   AND NAME = 'thread/sql/one_connection'
    ->   AND PROCESSLIST_ID IS NOT NULL
    -> GROUP BY PROCESSLIST_COMMAND
    -> ORDER BY thread_count DESC, command_name;

+--------------+--------------+-------------------+
| command_name | thread_count | max_state_seconds |
+--------------+--------------+-------------------+
| Query        |            1 |                 0 |
+--------------+--------------+-------------------+
1 row in set (0.00 sec)
```

이 집계에서 `Sleep`이 많다면 바로 연결을 강제 종료하기보다 connection pool의 최소·최대 크기, `wait_timeout`, 트래픽 패턴, 연결 생성 비용을 함께 확인한다. `Query`가 많고 `max_state_seconds`가 증가한다면 statement·wait·lock 자료로 범위를 좁힌다.

## 4. 열 대응 관계와 결정적 차이

두 인터페이스의 표면적인 열은 상당 부분 대응한다.

| `SHOW PROCESSLIST` | `performance_schema.threads` | 비고 |
|---|---|---|
| `Id` | `PROCESSLIST_ID` | 클라이언트 연결 식별자 |
| `User` | `PROCESSLIST_USER` | background thread에서는 표현이 다를 수 있음 |
| `Host` | `PROCESSLIST_HOST` | 포트 포함 여부와 표시 형식 확인 필요 |
| `db` | `PROCESSLIST_DB` | 현재 기본 스키마 |
| `Command` | `PROCESSLIST_COMMAND` | 큰 명령 분류 |
| `Time` | `PROCESSLIST_TIME` | 현재 상태 경과 시간 |
| `State` | `PROCESSLIST_STATE` | 순간적인 실행 단계 |
| `Info` | `PROCESSLIST_INFO` | SQL 텍스트 |

그러나 `threads`에는 `THREAD_ID`, `TYPE`, `NAME`, `PARENT_THREAD_ID`, 계측 플래그처럼 processlist 화면에 없는 내부 연결 정보가 있다. 이것이 단순한 출력 형식 차이보다 중요하다.

### 4.1 즉시성 대 조합 가능성

- `SHOW FULL PROCESSLIST`: 입력이 짧고 사람이 바로 판단하기 좋다.
- `threads`: 조건을 코드로 고정하고 반복 실행하거나 결과를 집계하기 좋다.
- `threads` + event 테이블: “누가 접속했는가”에서 “무슨 statement를 어느 정도 실행 중인가”로 확장할 수 있다.
- `threads` + lock 테이블: 대기 thread와 blocking thread의 연결 정보를 결합할 수 있다.

### 4.2 foreground와 background

processlist는 연결 관점의 초기 조사에 적합하다. `threads`는 서버 내부 background 활동까지 보려는 경우 더 자연스럽다. 다만 background thread 이름과 개수는 버전·기능·설정에 따라 달라질 수 있으므로 고정된 개수를 정상 기준으로 삼지 않는다.

### 4.3 권한과 노출 범위

두 방법의 결과 범위가 항상 같다고 가정하면 안 된다. 계정의 동적·정적 권한, Performance Schema 테이블 접근 권한, 관리형 서비스의 제한에 따라 다른 세션의 행이나 SQL 텍스트가 보이지 않을 수 있다. 진단 계정은 최소 권한 원칙을 유지하되, 실제 장애 대응에 필요한 가시성을 사전 점검해야 한다.

또한 SQL 텍스트에는 literal로 전달된 개인정보나 업무 데이터가 포함될 수 있다. processlist 결과를 티켓·메신저·모니터링 저장소에 옮길 때는 비밀값과 개인정보를 마스킹하고 보존 기간을 제한한다.

## 5. 현재 statement와 연결하기

`THREAD_ID`는 `events_statements_current`와 연결할 수 있다. 다음 쿼리는 현재 접속한 자기 세션을 대상으로 조인 구조와 대상 열의 존재를 안전하게 검증한다.

```sql
SELECT t.THREAD_ID,
       t.PROCESSLIST_ID,
       t.PROCESSLIST_COMMAND,
       e.EVENT_NAME,
       e.SQL_TEXT IS NOT NULL AS has_sql_text,
       e.ROWS_EXAMINED,
       e.ROWS_SENT
FROM performance_schema.threads AS t
LEFT JOIN performance_schema.events_statements_current AS e
  ON e.THREAD_ID = t.THREAD_ID
WHERE t.PROCESSLIST_ID = CONNECTION_ID();
```

실행 결과(MySQL 8.0.x):

```text
mysql> SELECT t.THREAD_ID,
    ->        t.PROCESSLIST_ID,
    ->        t.PROCESSLIST_COMMAND,
    ->        e.EVENT_NAME,
    ->        e.SQL_TEXT IS NOT NULL AS has_sql_text,
    ->        e.ROWS_EXAMINED,
    ->        e.ROWS_SENT
    -> FROM performance_schema.threads AS t
    -> LEFT JOIN performance_schema.events_statements_current AS e
    ->   ON e.THREAD_ID = t.THREAD_ID
    -> WHERE t.PROCESSLIST_ID = CONNECTION_ID();

+-----------+----------------+---------------------+----------------------+--------------+---------------+-----------+
| THREAD_ID | PROCESSLIST_ID | PROCESSLIST_COMMAND | EVENT_NAME           | has_sql_text | ROWS_EXAMINED | ROWS_SENT |
+-----------+----------------+---------------------+----------------------+--------------+---------------+-----------+
|        52 |             14 | Query               | statement/sql/select |            1 |             0 |         0 |
+-----------+----------------+---------------------+----------------------+--------------+---------------+-----------+
1 row in set (0.00 sec)
```

검증 예제는 출력이 불필요하게 길어지지 않도록 SQL 원문 대신 `has_sql_text`를 표시한다. 실제 운영에서는 필요한 경우 `e.SQL_TEXT`를 선택하고, 자기 세션 조건을 제거한 뒤 `NAME = 'thread/sql/one_connection'`, `PROCESSLIST_COMMAND <> 'Sleep'`, 경과 시간 기준 등을 추가할 수 있다. 다만 `events_statements_current`의 행과 값은 instrumentation 활성화 상태 및 관측 시점에 좌우된다. `LEFT JOIN` 결과에서 event 열이 `NULL`이라고 해서 해당 연결이 고장 났다고 판단할 수는 없다.

장기 실행 후보를 찾는 운영 쿼리의 예시 구조는 다음과 같다. `<관찰 기준 초>`는 환경의 SLO와 평상시 쿼리 분포에 맞춰 숫자로 바꾼다. placeholder가 있으므로 이 예시는 개념 구조이며 그대로 실행하는 SQL fence가 아니다.

```text
SELECT THREAD_ID, PROCESSLIST_ID, PROCESSLIST_USER,
       PROCESSLIST_HOST, PROCESSLIST_DB, PROCESSLIST_COMMAND,
       PROCESSLIST_TIME, PROCESSLIST_STATE, PROCESSLIST_INFO
FROM performance_schema.threads
WHERE TYPE = 'FOREGROUND'
  AND NAME = 'thread/sql/one_connection'
  AND PROCESSLIST_COMMAND <> 'Sleep'
  AND PROCESSLIST_TIME >= <관찰 기준 초>
ORDER BY PROCESSLIST_TIME DESC;
```

## 6. Time과 State를 오해하지 않는 법

### 6.1 `Time`은 트랜잭션 나이가 아니다

processlist의 `Time` 또는 `PROCESSLIST_TIME`은 현재 표시된 상태가 지속된 시간이다. 긴 트랜잭션을 찾으려면 `information_schema.INNODB_TRX.trx_started`, 변경 행 수, 현재 statement, Read View 유지 여부를 함께 조사해야 한다. `Sleep` 상태의 `Time`이 길어도 autocommit이 끝난 단순 idle connection일 수 있고, 반대로 비교적 짧은 statement가 반복되면서 전체 트랜잭션은 오래 열려 있을 수 있다.

### 6.2 `State`는 원인이 아니라 관찰 신호다

같은 state 문자열도 workload와 실행 단계에 따라 의미가 달라진다. 한 번의 snapshot에서 특정 문자열을 봤다는 이유로 즉시 `KILL`하거나 설정을 변경하지 않는다. 일정 간격으로 여러 번 관찰하고 statement digest, wait event, lock 관계, CPU·I/O 지표와 교차 확인한다.

### 6.3 `Sleep`은 무조건 제거 대상이 아니다

connection pool은 연결 생성 비용을 줄이기 위해 의도적으로 idle connection을 유지한다. 문제는 `Sleep` 자체가 아니라 다음 조건이다.

- `max_connections`에 가까워져 신규 연결이 실패한다.
- 애플리케이션 인스턴스 수와 pool 상한의 곱이 서버 수용량을 초과한다.
- 열린 트랜잭션을 가진 idle session이 undo purge나 lock 해제를 지연한다.
- 비정상 재시도로 연결 수가 지속적으로 증가한다.

## 7. 실무 진단 순서

다음 절차는 processlist를 출발점으로 삼되 단일 화면에 머물지 않도록 구성한 runbook이다.

```mermaid
flowchart TD
    A[SHOW FULL PROCESSLIST로 즉시 확인] --> B{이상 징후가 반복되는가}
    B -- 아니오 --> C[짧은 샘플 여러 번 수집]
    B -- 예 --> D[threads에서 조건·집계 고정]
    C --> D
    D --> E{주요 증상}
    E -- 장기 실행 --> F[events_statements_current/history 및 digest 확인]
    E -- 잠금 대기 --> G[data_lock_waits와 data_locks 연결]
    E -- 연결 고갈 --> H[명령·계정·호스트별 분포와 pool 설정 확인]
    E -- background 이상 --> I[NAME·TYPE과 관련 metric 확인]
    F --> J[실행계획·통계·I/O 조사]
    G --> K[blocking transaction과 commit 경계 확인]
    H --> L[pool 상한·timeout·재시도 정책 조정]
    I --> M[기능별 상태와 오류 로그 교차 확인]
```

1. **초기 snapshot 확보**: `SHOW FULL PROCESSLIST` 결과와 서버 시각, 연결 수, 오류율을 함께 기록한다.
2. **반복성 확인**: 수 초 간격으로 관찰하여 순간적인 상태와 지속되는 상태를 분리한다.
3. **관측 쿼리 고정**: `threads`에서 필요한 열과 조건만 선택해 동일한 기준으로 재측정한다.
4. **원인별 확장**: statement, wait, lock, transaction, digest 자료 중 증상에 맞는 테이블로 조인한다.
5. **애플리케이션 문맥 연결**: 연결 ID, 계정, DB, SQL digest를 배포 버전과 요청 경로에 연결한다.
6. **개입 전 영향 평가**: `KILL QUERY`, `KILL CONNECTION`, parameter 변경 전에 rollback 비용과 재시도 폭증 가능성을 확인한다.
7. **사후 기준선 보완**: 정상 시간대의 command 분포와 상위 digest를 저장해 다음 장애의 비교 기준으로 삼는다.

## 8. Aurora MySQL에서의 해석

Aurora MySQL에서도 `SHOW FULL PROCESSLIST`와 Performance Schema 기반 분석의 기본 개념은 동일하다. 다만 운영 판단에서는 다음 차이를 반영해야 한다.

- writer와 reader는 서로 다른 DB instance이다. 한 instance의 processlist만 보고 cluster 전체 세션 상태로 일반화하지 않는다.
- reader endpoint를 사용해도 실제 연결은 특정 reader instance에 배치된다. 연결 고갈이나 장기 실행은 instance별로 확인한다.
- failover 뒤에는 기존 연결이 끊기고 재접속이 몰릴 수 있다. processlist 급증을 DB 원인으로만 보지 말고 DNS, driver, pool 재연결 정책과 함께 본다.
- Performance Insights나 Database Insights에서 상위 SQL과 DB load를 먼저 찾고, `threads`와 Performance Schema 자료로 해당 시점의 세션 문맥을 좁힐 수 있다.
- parameter group에서 Performance Schema 관련 설정을 변경할 때 적용 범위와 재시작 필요 여부를 먼저 확인한다. 관리형 환경에서는 Community MySQL과 사용 가능한 consumer·instrument가 다를 수 있다.

Aurora의 분산 저장 구조는 processlist 열의 의미를 바꾸지는 않지만, I/O 지연이나 failover 원인을 한 instance의 `State` 문자열만으로 설명하기 어렵게 만든다. CloudWatch, Performance Insights, Aurora event, 오류 로그를 함께 보아야 한다.

## 9. 흔한 실패와 주의점

### 9.1 processlist 한 번만 캡처한다

짧은 SQL은 관찰 사이에 사라진다. 반대로 순간적인 장기 상태처럼 보이는 행도 다음 샘플에서 끝날 수 있다. 초기 대응 자동화는 여러 snapshot과 시각을 함께 저장해야 한다.

### 9.2 모든 `Sleep` 연결을 일괄 종료한다

pool이 즉시 재연결해 접속 폭증과 인증 부하를 만들 수 있다. 연결 수 계산, 열린 트랜잭션 여부, 애플리케이션 retry 정책을 먼저 확인한다.

### 9.3 `PROCESSLIST_ID`와 `THREAD_ID`를 혼용한다

`KILL`은 연결 ID를 사용한다. Performance Schema 조인은 `THREAD_ID`를 사용한다. 두 값을 같은 숫자라고 가정하지 않는다.

### 9.4 SQL 텍스트가 없으면 실행 중인 일이 없다고 판단한다

권한, instrumentation, 관측 타이밍, thread 종류에 따라 `Info` 또는 `SQL_TEXT`가 비어 있을 수 있다. command, state, event, transaction 자료를 함께 확인한다.

### 9.5 관측 자체의 비용을 무시한다

고빈도 polling, 전체 SQL 텍스트 수집, 큰 결과의 외부 전송은 바쁜 서버에 추가 부하와 보안 위험을 만든다. 필요한 열만 조회하고, 빈도·보존 기간·접근 권한을 제한한다.

## 10. 선택 기준과 운영 체크리스트

### 도구 선택 기준

| 상황 | 우선 선택 | 다음 단계 |
|---|---|---|
| 콘솔에서 즉시 전체 상황 확인 | `SHOW FULL PROCESSLIST` | 반복되면 `threads` 쿼리로 기준 고정 |
| 특정 조건의 연결을 자동 탐지 | `performance_schema.threads` | 집계·알림 규칙 적용 |
| statement/wait/lock과 연결 | `threads.THREAD_ID` | 관련 Performance Schema 테이블 조인 |
| 특정 연결을 종료 | processlist 연결 ID 확인 | rollback·재시도 영향 평가 후 `KILL` |
| background thread 조사 | `threads.NAME`, `TYPE` | 기능별 metric·로그 교차 확인 |
| Aurora cluster 장애 | instance별 두 방법 사용 | Performance Insights·CloudWatch·event 결합 |

### 발행·운영 점검표

- [ ] 긴 SQL 텍스트 확인에는 `SHOW FULL PROCESSLIST`를 사용한다.
- [ ] `Id`/`PROCESSLIST_ID`와 `THREAD_ID`의 역할을 구분한다.
- [ ] `Time`을 statement나 transaction의 전체 수명으로 단정하지 않는다.
- [ ] 한 번의 `State` snapshot만으로 원인을 확정하지 않는다.
- [ ] `threads` 결과를 statement, wait, lock 자료와 연결할 때 `THREAD_ID`를 사용한다.
- [ ] 진단 계정의 가시성과 최소 권한을 사전에 시험한다.
- [ ] SQL 텍스트를 외부에 저장할 때 개인정보와 비밀값을 마스킹한다.
- [ ] `Sleep` 정리 전 connection pool과 열린 트랜잭션을 확인한다.
- [ ] Aurora MySQL은 writer/reader instance별로 관찰한다.
- [ ] 개입 전 `KILL`에 따른 rollback 비용과 재시도 폭증 가능성을 평가한다.

## 11. 결론

`SHOW FULL PROCESSLIST`는 장애 현장에서 가장 빠른 첫 화면이고, `performance_schema.threads`는 그 화면을 반복 가능한 SQL 진단과 statement·wait·lock 분석으로 확장하는 기준 테이블이다. 핵심은 어느 하나를 대체재로 고르는 것이 아니라, processlist로 이상 징후를 포착하고 `THREAD_ID`를 중심으로 Performance Schema 자료를 연결하는 것이다.

다음 단계에서는 `events_statements_current`, statement history, digest 집계를 구분하고, 짧아서 processlist에서 놓치기 쉬운 SQL을 어떻게 누적 관측할지 살펴볼 수 있다. 세션 snapshot과 누적 workload 통계를 구분할 수 있어야 일시적인 현상과 구조적인 병목을 정확히 나눌 수 있다.
