SHOW PROCESSLIST와 performance_schema.threads 비교
MySQL 세션 관측의 두 출발점인 SHOW PROCESSLIST와 performance_schema.threads의 데이터 구조, 활용 범위, 권한, 운영 진단 절차를 비교한다.
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로 조인할 수 있다는 점이 핵심이다.
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: 빠른 현장 확인
기본 명령은 다음 두 가지이다.
SELECT VERSION() AS mysql_version,
CONNECTION_ID() AS connection_id,
@@performance_schema AS performance_schema_enabled;
SHOW FULL PROCESSLIST;
실행 결과(MySQL 8.0.x):
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가 특히 유용한 상황은 다음과 같다.
- 장애 직후 5~10초 안에 전체 연결 분포를 빠르게 확인할 때
- 특정 연결 ID가 살아 있는지 확인할 때
Sleep, 장기 실행, 특정State가 비정상적으로 몰리는지 육안으로 볼 때- 추가 쿼리를 작성할 여유가 없는 초기 대응 단계
그러나 출력은 한 시점의 snapshot이다. 1초 뒤에는 행과 상태가 달라질 수 있으며, 높은 Time 값 하나만으로 CPU 병목·잠금 대기·긴 트랜잭션을 구분할 수 없다.
3. performance_schema.threads: 관계형 진단의 기준점
threads 테이블은 foreground 연결뿐 아니라 MySQL 내부 background thread도 포함할 수 있다. 먼저 대상 서버에서 Performance Schema와 테이블 존재 여부를 확인한다.
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):
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도 확인한다.
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):
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와 연결할 수 있다. 다음 쿼리는 현재 접속한 자기 세션을 대상으로 조인 구조와 대상 열의 존재를 안전하게 검증한다.
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):
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가 아니다.
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이다.
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[기능별 상태와 오류 로그 교차 확인]
- 초기 snapshot 확보:
SHOW FULL PROCESSLIST결과와 서버 시각, 연결 수, 오류율을 함께 기록한다. - 반복성 확인: 수 초 간격으로 관찰하여 순간적인 상태와 지속되는 상태를 분리한다.
- 관측 쿼리 고정:
threads에서 필요한 열과 조건만 선택해 동일한 기준으로 재측정한다. - 원인별 확장: statement, wait, lock, transaction, digest 자료 중 증상에 맞는 테이블로 조인한다.
- 애플리케이션 문맥 연결: 연결 ID, 계정, DB, SQL digest를 배포 버전과 요청 경로에 연결한다.
- 개입 전 영향 평가:
KILL QUERY,KILL CONNECTION, parameter 변경 전에 rollback 비용과 재시도 폭증 가능성을 확인한다. - 사후 기준선 보완: 정상 시간대의 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 - 한 번의
State -
threads결과를 statement, wait, lock 자료와 연결할 때THREAD_ID -
Sleep - 개입 전
KILL
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 통계를 구분할 수 있어야 일시적인 현상과 구조적인 병목을 정확히 나눌 수 있다.