0Pricing
Coding Interview Prep · 강의

느린 쿼리 찾기와 수정

‘이 쿼리가 느린데 수정해 보세요’라는 면접 질문을 위한 진단 체크리스트입니다.

느린 쿼리 찾기와 수정은(는) CoddyKit의 무료 Coding Interview Prep 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Coding Interview Prep 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.

「이 쿼리는 느립니다. 고쳐 보세요」 질문

이것은 종합 면접 질문입니다. 면접관이 느린 쿼리와 EXPLAIN ANALYZE 실행 계획을 제시하고 진단해 보라고 합니다. 면접관이 평가하는 것은 외워 둔 요령이 아니라 방법입니다.

좋은 답변은 다음 점검 목록을 소리 내어 따라갑니다. 측정하고, 실행 계획을 읽고, 가장 큰 비용을 찾고, 가설을 세우고, 해결책을 제안한 뒤, 검증합니다. 이 강의에서는 이 점검 목록을 단계별로 익힙니다.

체계적으로 접근하고 추론 과정을 설명하십시오. 그것이 시니어 수준의 평가를 받는 방법입니다.

1단계: EXPLAIN ANALYZE로 측정하기

SQL만 보고 절대 추측하지 마십시오. EXPLAIN (ANALYZE, BUFFERS)로 실제 실행 계획을 확인하십시오.

ANALYZE는 실제 실행 시간과 행 수를 제공하고, BUFFERS는 캐시를 사용하는지 디스크에서 읽는지를 보여 줍니다. 두 정보를 함께 보면 쿼리가 CPU 병목인지, 입출력 병목인지, 아니면 단순히 작업을 너무 많이 수행하는지 알 수 있습니다.

두어 번 실행하십시오. 첫 번째 실행에서는 캐시가 비어 있을 때의 불이익이 발생하여 시간이 왜곡될 수 있습니다.

EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.created_at >= '2026-01-01';

2단계: 가장 큰 비용의 노드 찾기

무작위로 위에서 아래까지 읽지 마십시오. 실제로 가장 많은 시간이 소비되는 노드를 찾으십시오.

각 노드의 자체 시간을 계산하십시오. 전체 actual time에서 자식 노드의 시간을 뺀 뒤 loops를 곱합니다. 가장 큰 비중을 차지하는 노드가 집중할 대상이고 나머지는 잡음입니다.

면접에서는 다음과 같이 말하십시오: 실행 시간의 80퍼센트가 이 순차 스캔 하나에서 발생하므로 여기에 집중하겠습니다. 다른 부분을 최적화하는 것은 노력 낭비입니다.

3단계: 추정치와 실제 값 비교

가장 큰 비용의 노드에서 추정 행 수와 실제 행 수를 비교하십시오. 큰 차이가 있다면 플래너가 충분한 정보 없이 판단하고 있으며 잘못된 실행 계획(잘못된 조인 알고리즘이나 잘못된 접근 방식)을 선택했을 가능성이 큽니다.

예시에서는 1,000배 과소 추정이 발생합니다. 무엇인가를 재설계하기 전에 통계를 갱신하십시오. 이 한 명령만으로 추가 비용 없이 실행 계획이 수정되는 경우가 많습니다.

ANALYZE는 열 통계를 다시 계산하고, VACUUM ANALYZE는 삭제된 튜플도 정리하며 가시성 맵을 갱신합니다.

-- estimate rows=100, actual rows=120000  -> stale stats
ANALYZE orders;
-- or, for bloated tables:
VACUUM ANALYZE orders;

흔한 원인: 인덱스 열에 적용한 함수

가장 흔하고 수정할 수 있는 버그는 WHERE에서 함수나 형변환이 열을 감싸는 경우입니다. 그러면 인덱스를 사용할 수 없어 엔진이 순차 스캔을 수행합니다.

예시에서는 모든 행에 DATE()를 적용하기 때문에 전체 스캔이 강제됩니다. 이를 열 자체를 사용하는 범위 조건식(검색 가능한 형태)으로 다시 작성하면 created_at의 인덱스가 사용됩니다.

WHERE lower(email)=...도 같은 원리입니다. 정규화된 데이터를 저장하거나, 열 자체를 조회하거나, 표현식 인덱스를 생성하십시오.

-- Not sargable: index unusable
WHERE DATE(created_at) = '2026-01-01'

-- Sargable: range over the bare column
WHERE created_at >= '2026-01-01'
  AND created_at <  '2026-01-02'

흔한 원인: 인덱스 누락

가장 큰 비용의 노드가 선택도가 높은 필터를 사용하는 순차 스캔이거나, 인덱스가 없는 내부 키에서 loops가 매우 큰 중첩 루프라면 해결책은 보통 인덱스입니다.

필터링하거나 조인하는 열에 인덱스를 추가하십시오. 예시에서는 customer_id에 인덱스를 생성하여 조인이 순차 스캔에서 인덱스 스캔으로 전환될 수 있게 합니다. 그러면 플래너가 훨씬 저렴한 실행 계획을 선택할 수 있습니다.

EXPLAIN ANALYZE를 다시 실행하여 확인하십시오. 인덱스가 도움이 되었다고 가정하지 마십시오.

CREATE INDEX idx_orders_customer
  ON orders (customer_id);

흔한 원인: SELECT *와 열이 많은 행

SELECT *는 디스크에서 모든 열을 읽어 네트워크로 전송하게 하며, 인덱스가 모든 열을 포함하는 경우가 드물기 때문에 인덱스만 사용하는 스캔도 방해합니다.

필요한 열만 선택하십시오. 그러면 행 너비가 줄고 입출력이 감소하며 모든 필요한 열을 포함하는 인덱스만 사용한 스캔이 가능해질 수 있습니다.

면접관이 SELECT *를 일부러 넣었다면 이를 알아차리기를 기대하는 것입니다. 열 목록을 줄이는 것은 열이 많은 테이블에서 빠르고 실제적인 효과를 내는 경우가 많습니다.

-- Before
SELECT * FROM orders WHERE customer_id = 42;

-- After: only needed columns (may enable index-only scan)
SELECT order_id, amount FROM orders WHERE customer_id = 42;

흔한 원인: 디스크로 넘치기

Sort 또는 Hash 노드가 디스크 사용량을 보고한다면(Sort Method: external merge Disk: 25000kB 또는 Batches: > 1), 작업이 work_mem을 초과하여 디스크로 넘친 것입니다.

방법은 여러 가지입니다. 세션의 work_mem을 늘리거나, 정렬 또는 해시에 도달하는 행 수를 줄이거나(더 일찍 필터링), 정렬된 순서를 제공하는 인덱스를 추가하여 정렬 자체가 필요 없게 할 수 있습니다.

이는 면접관이 높이 평가하는 정확한 시니어 수준의 진단입니다.

Sort  (actual rows=2000000 loops=1)
  Sort Key: o.amount
  Sort Method: external merge  Disk: 25000kB

흔한 원인: 행을 과다 조회하기

Rows Removed by Filter: 9500000을 주의해서 보십시오. 쿼리가 천만 개의 행을 읽고 거의 전부 버린 것입니다. 전형적인 작업 낭비입니다.

해결책은 필터가 접근 후가 아니라 접근 중에 적용되도록 인덱스를 추가하거나, 조건식의 선택도를 높이거나, 쿼리에서 필터링을 더 앞 단계로 이동하여 실행 계획 트리 위로 전달되는 행 수를 줄이는 것입니다.

원칙은 가장 적은 작업만 수행하는 것입니다. 가능한 한 이르고 저렴하게 필터링하십시오.

Seq Scan on events
  Filter: (event_type = 'purchase')
  Rows Removed by Filter: 9500000

진단 점검 목록

면접에서 다음을 그대로 말하면 방향을 잃지 않을 수 있습니다:

  • 측정: EXPLAIN (ANALYZE, BUFFERS)를 사용합니다.
  • 찾기: 가장 많은 시간을 소비하는 노드를 찾습니다.
  • 비교: 추정 행 수와 실제 행 수를 비교하고, 먼저 오래된 통계를 수정합니다.
  • 검색 가능성 확인: 필터링하는 열에서 함수를 제거합니다.
  • 인덱스 생성: 선택도가 높은 필터와 조인 키에 인덱스를 생성합니다.
  • 줄이기: 열 수를 줄이고 SELECT *를 피합니다.
  • 살피기: 디스크로 넘치는 작업과 행 과다 조회를 확인합니다.
  • 검증: 실행 계획을 다시 실행하여 확인합니다.

종합하기

전체 예제를 소리 내어 설명해 보십시오. 실행 계획에는 5천만 행의 orders 테이블에 대한 순차 스캔, customer_id = 42 필터, 5천만에 가까운 Rows Removed by Filter가 표시되고, 추정치가 실제값과 대략 일치한다고 가정합니다.

진단 결과는 선택도가 높은 필터가 있지만 인덱스가 없고, 지배적인 비용은 스캔이라는 것입니다. 해결 방법은 CREATE INDEX ON orders(customer_id)입니다. 다시 실행하면 실행 계획이 인덱스 스캔으로 바뀌고, 시간이 수 초에서 1밀리초 미만으로 줄어듭니다.

이 측정-진단-수정-검증 순환이 느린 질의 질문에 답할 때 사용하는 기본 답변 틀입니다.

CREATE INDEX idx_orders_customer ON orders (customer_id);
EXPLAIN (ANALYZE, BUFFERS)
SELECT order_id, amount FROM orders WHERE customer_id = 42;

빠른 점검

WHERE YEAR(order_date) = 2026으로 필터링하는 질의가 있고, order_date에 기존 B-트리 인덱스가 있는데도 실행 계획에 전체 순차 스캔이 표시됩니다. 가장 먼저 적용할 해결 방법은 무엇입니까?

요약

이제 느린 질의 질문에 반복해서 적용할 수 있는 방법을 익혔습니다.

  • 항상 EXPLAIN (ANALYZE, BUFFERS)로 측정하고 주요 노드에 집중하십시오.
  • 추정치와 실제값이 크게 다르면 먼저 오래된 통계를 수정하십시오.
  • 조건식을 검색 가능한 형태로 만들고, 선택도가 높은 필터와 조인 키에 인덱스를 추가하며, SELECT *를 줄이십시오.
  • 디스크로 넘치는 작업과 과도한 데이터 조회를 해결한 다음 새 실행 계획을 검증하십시오.

체크리스트를 설명하고, 구체적인 변경을 제안한 뒤, 실행 계획을 다시 실행해 그 효과를 입증하는 것이 시니어다운 답변입니다.

자주 묻는 질문

“느린 쿼리 찾기와 수정” 강의는 무료인가요?

네 — “느린 쿼리 찾기와 수정” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Coding Interview Prep 강의 전체를 잠금 해제할 수 있습니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.

“느린 쿼리 찾기와 수정”에서 뭘 배우나요?

‘이 쿼리가 느린데 수정해 보세요’라는 면접 질문을 위한 진단 체크리스트입니다. 브라우저에서 직접 실행하는 실습 코드로 Coding Interview Prep을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Coding Interview Prep을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Coding Interview Prep은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“느린 쿼리 찾기와 수정” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Coding Interview Prep 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Coding Interview Prep 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. EXPLAIN 계획 읽기
  2. 순차 스캔, 인덱스 스캔, 인덱스 전용 스캔 비교
  3. 조인 알고리즘: 중첩 루프, 해시, 병합
  4. 느린 쿼리 찾기와 수정
← Coding Interview Prep(으)로 돌아가기