개요
2025.09.19-[PostgreSQL] EXPLAIN - 1에서 EXPLAIN에 대한 기초적인 부분을 살펴봤다. 이어서 이번 글에서는 다른 절이 추가됨에 따라 달라지는 실행 계획을 살펴보려고 한다.
LIMIT
LIMIT을 추가하면 플래너는 모든 행을 검색할 필요가 없도록 수행할 작업을 변경한다. Index Scan 노드가 완료될 때까지 실행되는 것처럼 표시되지만 Limit 노드는 해당 행 중 3개 행만 검색한 후에 중지될 것이라 예상한다. 때문에 총비용도 그만큼 감소하게 된다.
EXPLAIN
SELECT *
FROM license_integrated
WHERE collect_status = 'DONE'
ORDER BY license_id
LIMIT 3
;
JOIN - Nested Loop
Join의 경우에는 실행 계획이 몇 가지로 나뉠 수 있는데, 아래의 경우에는 두 개의 테이블 스캔을 입력으로 하는 Nested Loop 조인 노드를 사용한다.
EXPLAIN
SELECT *
FROM license_integrated a, license_integrated b
WHERE a.license_id = b.license_id
AND a.latest_date = '2025-09-01'
첫 번째 자식 노드는 Seq Scan으로 이 노드는 단순히 테이블에 WHERE lasted_date = '2025-09-01'을 수행한 것과 동일한 계획이라고 할 수 있다. 그리고 Nested Loop 노드는 첫 번째 자식 노드에서 얻은 데이터로 두 번째 자식 노드를 실행한다.
참고로 조인을 수행할 때 먼저 처리되는 테이블을 외부 테이블 또는 구동 테이블이라고 하고, 다른 테이블을 내부 테이블이라고 한다.
JOIN - Hash Join
쿼리 선택 범위를 다르게 하면 다른 조인 실행 계획을 얻을 수 있다.
EXPLAIN
SELECT *
FROM license_integrated a, license_integrated b
WHERE a.license_id = b.license_id
AND a.latest_date > '2025-09-01'
;
여기서 플래너는 인메모리 해시 테이블에 입력한 후 다른 테이블을 스캔하고 해시 테이블에서 각 행의 일치 여부를 조사하는 해시 조인을 사용하기로 했다. b 테이블에서의 Seq Scan이 해시 테이블을 구성하는 해시 노드에 대한 입력이다. 만들어진 해시 테이블은 Hash Join 노드로 반환되고, a 테이블을 스캔하며 결합 키가 해시값에 존재하는지 확인하며 결합을 수행한다.
해시 테이블은 메모리에 저장되므로 일반적으로 작은 테이블을 이용해 만든다.
JOIN - Merge Join
조인의 다은 유형은 Merge Join이다. 내 예시 테이블에서는 적절한 쿼리를 찾지 못해서 다른 예시로 대체한다.
QUERY PLAN
--------------------------------------------------------------------------------
Merge Join (cost=198.11..268.19 rows=10 width=488)
Merge Cond: (t1.unique2 = t2.unique2)
-> Index Scan using tenk1_unique2 on tenk1 t1 (cost=0.29..656.28 rows=101 width=244)
Filter: (unique1 < 100)
-> Sort (cost=197.83..200.33 rows=1000 width=244)
Sort Key: t2.unique2
-> Seq Scan on onek t2 (cost=0.00..148.00 rows=1000 width=244)
Merge Join을 사용하려면 조인 키로 입력 데이터를 정렬해야 한다. 때문에 Sort Merge라고도 부른다. 이 계획에서 tenk1 데이터는 인덱스 스캔을 사용해 읽고, onek은 행이 많아 인덱스 스캔 대신 순차적 스캔을 하고 정렬을 수행한다.
인덱스는 디스크의 물리적 저장 위치를 기준으로 정렬되어 있는 것이 아니기 때문에 데이터가 많은 경우 순차 스캔 및 정렬이 인덱스 스캔보다 나은 경우가 많다. 디스크에서 데이터를 실제로 가지고 오는 데 걸리는 시간 때문이다.
참고 문서
https://datarian.io/blog/postgresql-using-explain