CodeGym /행동 /SQL SELF /실행 계획 해석하기: 노드 읽기와 분석하기 (`Seq Scan`, `Index Scan`, `Hash ...

실행 계획 해석하기: 노드 읽기와 분석하기 (`Seq Scan`, `Index Scan`, `Hash Join`)

SQL SELF
레벨 41 , 레슨 4
사용 가능

오늘은 PostgreSQL 실행 계획의 노드가 뭔지, 그걸 어떻게 읽는지, 그리고 제일 중요한 건 뭔가 잘못됐을 때 그걸 어떻게 알아차리는지 알아볼 거야. 왜 가끔 데이터베이스가 이미 인덱스가 있는데도 리소스를 많이 쓰는 Seq Scan을 쓰는지, 그 이유도 알 수 있을 거야.

PostgreSQL이 쿼리 실행 계획을 만들 때, 그걸 여러 단계로 쪼개는데, 이걸 노드라고 불러. 각 노드는 데이터베이스 서버가 네 쿼리를 처리할 때 거치는 "단계" 같은 거야. 주요 노드 타입은 다음과 같아:

Sequential Scan (Seq Scan)

Seq Scan 또는 순차 스캔은 테이블에서 데이터를 뽑아내는 제일 단순한 방법이야. PostgreSQL은 테이블을 그냥 한 줄씩 다 읽으면서 네 쿼리 조건에 맞는지 확인해.

Seq Scan이 언제 쓰일까?
Seq Scan은 이런 경우에 써:

  • 테이블에 쿼리를 빠르게 해줄 만한 인덱스가 없을 때.
  • 필터 조건이 너무 넓어서 인덱스가 별로 쓸모없을 때(예를 들어, 전체 데이터의 50% 이상을 뽑아야 할 때).
  • PostgreSQL이 인덱스 쓰는 것보다 그냥 테이블을 쭉 읽는 게 더 빠르다고 판단할 때(진짜 작은 테이블에서 가끔 이럴 수 있어).
EXPLAIN SELECT * FROM students WHERE age > 18;

결과 예시:

Seq Scan on students  (cost=0.00..35.50 rows=10 width=50)
  Filter: (age > 18)

Seq Scan on students를 보면, PostgreSQL이 "students" 테이블을 전부 읽겠다는 뜻이야.

Seq Scan의 문제점: 테이블이 엄청 크면, 순차 스캔은 진짜 오래 걸릴 수 있어.

Index Scan

Index Scan은 인덱스를 이용해서 데이터를 읽는 거야. PostgreSQL에서 인덱스를 만들면, 테이블의 "목차" 같은 게 생기는 거지. 쿼리가 인덱스를 쓸 수 있으면, PostgreSQL은 테이블 전체를 읽지 않고 필요한 부분만 빠르게 찾아가.

Index Scan이 언제 쓰일까?

  • 쿼리에서 인덱스가 걸린 컬럼에 필터 조건(WHERE 등)이 있을 때.
  • =, <, >, BETWEEN 같은 비교 연산을 쓸 때.
CREATE INDEX idx_students_age ON students(age);

EXPLAIN SELECT * FROM students WHERE age = 18;

결과 예시:

Index Scan using idx_students_age on students  (cost=0.15..8.27 rows=1 width=50)
  Index Cond: (age = 18)

여기서 Index Scan using idx_students_age는 PostgreSQL이 idx_students_age 인덱스를 쓴다는 뜻이야. 테이블을 한 줄씩 읽는 게 아니라, 인덱스를 통해 훨씬 빠르게 접근하지.

Index Scan의 장점:

  • 큰 테이블에서 쿼리 속도가 확 빨라져.
  • 디스크에서 읽는 데이터 양이 줄어들어.

Index Scan의 문제점:
쿼리 결과가 너무 많으면(예를 들어, 테이블의 절반 이상), 인덱스를 쓰는 게 오히려 Seq Scan보다 느릴 수도 있어.

Hash Join

Hash Join은 두 테이블을 조인할 때 써(예: ON students.course_id = courses.id). PostgreSQL은 두 테이블 중 더 작은 쪽으로 해시 테이블을 만들고, 그걸로 다른 테이블에서 매칭되는 값을 찾아.

Hash Join이 언제 쓰일까?

  • INNER JOIN, LEFT JOIN 등으로 테이블을 조인할 때.
  • PostgreSQL이 Hash Join이 다른 조인 방식보다 더 효율적이라고 판단할 때.
EXPLAIN
SELECT * 
FROM students 
JOIN courses ON students.course_id = courses.id;

결과 예시:

Hash Join  (cost=25.00..50.00 rows=10 width=100)
  Hash Cond: (students.course_id = courses.id)
  -> Seq Scan on students  (cost=0.00..20.00 rows=10 width=50)
  -> Hash  (cost=15.00..15.00 rows=10 width=50)
       -> Seq Scan on courses  (cost=0.00..15.00 rows=10 width=50)

여기서 Hash Join이 두 테이블을 조인해. PostgreSQL이 먼저 두 테이블 모두 Seq Scan을 하고, 그 다음에 해시 테이블(Hash)을 만들어.

Hash Join의 장점:

  • 중간 크기 테이블에서 빠르게 처리할 수 있어.
  • 행이 많은 테이블 조인에도 효율적이야.

Hash Join의 문제점:
해시 테이블 크기가 메모리보다 크면, PostgreSQL이 디스크를 써야 해서 조인이 엄청 느려질 수 있어.

실행 계획 분석 예시

실제 예시로 한 번 분석해보자.

쿼리:

EXPLAIN ANALYZE
SELECT *
FROM students
JOIN courses ON students.course_id = courses.id
WHERE students.age > 18;

결과:

Hash Join  (cost=35.00..75.00 rows=5 width=100) (actual time=1.00..2.50 rows=5 loops=1)
  Hash Cond: (students.course_id = courses.id)
  -> Seq Scan on students  (cost=0.00..40.00 rows=10 width=50) (actual time=0.50..1.00 rows=7 loops=1)
        Filter: (age > 18)
        Rows Removed by Filter: 3
  -> Hash  (cost=25.00..25.00 rows=5 width=50) (actual time=0.30..0.30 rows=5 loops=1)
       -> Seq Scan on courses  (cost=0.00..20.00 rows=5 width=50) (actual time=0.20..0.25 rows=5 loops=1)
Planning Time: 0.50 ms
Execution Time: 3.00 ms

해석:

  1. Hash Join: 메인 노드야. PostgreSQL이 studentscourses 테이블을 조인해.
    • actual time: 1.00~2.50ms.
    • rows=5: 쿼리 결과로 5행이 나왔어.
  2. 안에 들어있는 노드들:
    • Seq Scan on students: students 테이블을 순차적으로 읽으면서 (age > 18) 필터를 적용해.
    • Rows Removed by Filter = 3: 조건에 안 맞아서 걸러진 행이 3개야.
    • Hash: PostgreSQL이 courses 테이블로 해시 테이블을 만들어.

노드 비교와 선택

실행 계획을 분석할 때, PostgreSQL이 왜 특정 데이터 처리 방식을 골랐는지 이해하는 게 핵심이야. 가끔은 네가 직접 개입해서 인덱스를 추가하거나 쿼리를 고쳐야 할 수도 있어. 몇 가지 팁을 줄게:

  • 큰 테이블에서 Seq Scan이 보이면, 인덱스를 고민해봐.
  • Hash Join이 너무 느리면, PostgreSQL에 할당된 메모리를 확인해봐.
  • EXPLAIN ANALYZE로 예상 값이랑 실제 값(rows, time 등)을 비교해봐.

이제 쿼리 실행 계획을 읽고, 노드를 해석하는 기본은 잡았어. 다음 강의에서는 자주 나오는 최적화 문제랑 그 해결법을 다룰 거야.

2
과제
SQL SELF, 레벨 41, 레슨 4
잠금
인덱스와 `Index Scan` 노드 사용하기
인덱스와 `Index Scan` 노드 사용하기
1
설문조사/퀴즈
쿼리 실행 계획, 레벨 41, 레슨 4
사용 불가능
쿼리 실행 계획
쿼리 실행 계획
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION