DBAtlas · 데이터베이스 운영 아틀라스

높은 CPU

서버 CPU가 포화 상태다. 먼저 실제로 데이터베이스가 소비하는지 확인한 뒤 분기를 따라 근본 원인으로 간다: 실행 계획이 나쁜 쿼리, 실행 계획 회귀, 과도한 동시성, 또는 DB가 아닌 프로세스.

실제로 데이터베이스가 CPU를 소비하는가?

운영체제 측에서 어떤 프로세스가 CPU를 소비하는지 확인한다. 부하 대부분이 DB 프로세스에 있는가, 아니면 이웃 프로세스(백업, 백신, 다른 애플리케이션)에 있는가? 이에 따라 조사가 둘로 나뉜다.

-- OS side: top -o %CPU  (or: top -c)
-- DB-side verification:
SELECT ROUND(value,1) AS host_cpu_util_pct FROM v$sysmetric WHERE metric_name='Host CPU Utilization (%)' AND rownum=1;
  • 예, DB 프로세스가 CPU를 소비한다
  • 아니요, 이웃 프로세스 / 백업 작업이 소비한다

부하가 어떻게 나타났는가?

DB가 CPU를 소비한다면 패턴을 파악한다: 무거운 쿼리 몇 개가 지배적인가, 변경 후 문제가 갑자기 시작되었는가, 아니면 높은 동시성/연결 경합이 있는가?

  • 무거운 쿼리 몇 개가 CPU를 소비한다
  • 갑자기 시작되었다. 최근 배포 / 파라미터 변경이 있었다
  • 연결 과다 / 동시성 경합

CPU를 가장 많이 소비하는 쿼리 찾기

총 CPU 소비 기준 상위 쿼리를 가져온다. 그다음 각 쿼리가 호출당 무거운지(나쁜 실행 계획), 호출당 가볍지만 매우 자주 호출되는지 판단한다.

SELECT sql_id, executions, ROUND(cpu_time/1e6,1) AS cpu_sec, ROUND(cpu_time/GREATEST(executions,1)/1000,2) AS cpu_ms_per_exec, sql_text
FROM v$sql ORDER BY cpu_time DESC FETCH FIRST 10 ROWS ONLY;
  • 호출당 무겁다. 나쁜 실행 계획 / full scan
  • 호출당 가볍지만 매우 자주 호출된다

근본 원인: 실행 계획이 나쁜 쿼리가 CPU를 소비함

몇몇 쿼리가 full scan이나 나쁜 조인 순서 때문에 호출당 과도한 CPU를 소비한다. 이들의 실행 계획을 고치는 것이 핵심 해결책이다.

근본 원인: 과도한 호출 빈도

쿼리 하나하나는 가볍지만 초당 수천 번 호출되어 총 CPU 비용이 여기서 나온다. 보통 N+1 패턴이나 캐시되지 않은 hot path다.

근본 원인: 실행 계획 회귀 / 오래된 통계

어제는 시스템이 정상이었다. 배포, 파라미터 변경, 데이터 적재 후 CPU가 급증했다. 옵티마이저가 더 나쁜 실행 계획으로 바뀌었을 수 있다.

근본 원인: 높은 동시성 / 연결 경합

개별 쿼리는 수용 가능하지만 너무 많은 세션이 동시에 실행된다. CPU 코어보다 많은 활성 세션은 context switching과 latch/spin 경합을 일으킨다.

근본 원인: DB가 아닌 프로세스가 CPU를 소비함

데이터베이스가 아니라 이웃 프로세스가 CPU를 소비한다: 같은 머신의 백업/압축 작업, 백신 스캔, log shipper, 또는 다른 애플리케이션.

DBAtlas에서 열기 →