2025. 2. 16. 16:24ㆍDatabase/PostgreSQL
데이터베이스에서 조인(Join)은 가장 중요한 연산 중 하나이며, 조인 방식에 따라 성능이 크게 달라질 수 있습니다. PostgreSQL은 기본적으로 다음 세 가지 조인 알고리즘을 사용합니다
- 해시 조인 (Hash Join)
- 중첩 루프 조인 (Nested Loop Join)
- 병합 조인 (Merge Join)
이 글에서는 각 조인 방식의 동작 원리, 장단점, 사용 조건을 깊이 있게 분석하고, EXPLAIN ANALYZE
를 활용한 실제 테스트 결과도 비교하겠습니다.
1. 해시 조인 (Hash Join)
원리
- 작은 테이블(혹은 조인 키의 작은 부분 집합)을 해시 테이블(Hash Table)로 생성합니다.
- 큰 테이블을 스캔하면서 해시 테이블을 참조하여 빠르게 조인합니다.
조건
- 등가 조인(Equal Join,
=
연산자 사용)에만 적용 가능 - 조인하는 두 테이블 중 적어도 하나는 메모리에 적재할 수 있어야 성능이 좋음
장점
✅ 테이블 크기가 크고 인덱스가 없을 때 효율적
✅ 랜덤 접근을 최소화하여 디스크 I/O를 줄일 수 있음
✅ 정렬이 필요하지 않음
단점
❌ 메모리를 많이 사용하며, 해시 테이블이 클 경우 디스크로 스왑될 가능성이 있음
❌ 비등가 조인 (>
, <
등)에는 사용할 수 없음
❌ 해시 테이블을 생성하는 오버헤드가 존재
예제 및 실행 계획
EXPLAIN ANALYZE
SELECT *
FROM orders o
JOIN customers c ON o.customer_id = c.id;
출력 예시
Hash Join (cost=5000.00..10000.00 rows=100000 width=200) (actual time=10.5..20.1 rows=100000 loops=1)
Hash Cond: (o.customer_id = c.id)
-> Seq Scan on orders o (cost=0.00..5000.00 rows=100000 width=100)
-> Hash (cost=2000.00..2000.00 rows=50000 width=100)
-> Seq Scan on customers c (cost=0.00..2000.00 rows=50000 width=100)
해시 조인 특징
Hash Cond
는 조인 조건을 의미합니다.Hash
연산은 고객 테이블을 해시 테이블로 만들었다는 뜻입니다.Seq Scan
이 사용되었으므로 테이블 풀 스캔을 수행했습니다.
2. 중첩 루프 조인 (Nested Loop Join)
원리
- 외부 테이블(Outer Table)을 한 줄씩 순회하면서, 내부 테이블(Inner Table)에서 조인 조건을 만족하는 행을 찾음
- 내부 테이블에서 인덱스가 있다면 성능이 크게 향상됨
조건
- 인덱스가 존재하면 매우 빠름
- 작은 테이블이 외부 테이블(Loop의 바깥쪽)일 때 유리
장점
✅ 인덱스가 있는 경우 매우 효율적
✅ 작은 데이터셋에서는 빠르고 메모리 사용량이 적음
단점
❌ 큰 테이블에서는 성능이 매우 나쁨 (O(N*M))
❌ 내부 테이블에 적절한 인덱스가 없으면 비효율적
예제 및 실행 계획
EXPLAIN ANALYZE
SELECT *
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE c.name = 'Alice';
출력 예시
Nested Loop (cost=5000.00..10000.00 rows=100000 width=200) (actual time=10.5..200.1 rows=100000 loops=1)
-> Seq Scan on customers c (cost=0.00..5000.00 rows=1 width=100) (actual time=0.5..1.0 rows=1 loops=1)
Filter: (name = 'Alice')
-> Index Scan using orders_customer_id_idx on orders o (cost=0.00..5000.00 rows=100000 width=100)
중첩 루프 조인 특징
Index Scan
이 사용되었기 때문에 내부 테이블 검색이 최적화됨Seq Scan
이 있으면 성능이 떨어질 가능성이 있음
3. 병합 조인 (Merge Join)
원리
- 두 테이블을 정렬한 후 병합(Merge)하여 조인하는 방식
- 정렬된 데이터가 있을 때 매우 빠르게 조인 가능
조건
- 두 테이블이 조인 키 기준으로 정렬되어 있어야 함
ORDER BY
를 포함한 쿼리에서 자주 사용됨
장점
✅ 대용량 테이블 조인 시 매우 효율적
✅ 디스크 I/O가 적음
✅ 비교적 메모리 사용량이 낮음
단점
❌ 정렬이 필요할 경우 추가 비용 발생
❌ 등가 조인(Equal Join)에만 사용 가능
예제 및 실행 계획
EXPLAIN ANALYZE
SELECT *
FROM orders o
JOIN customers c ON o.customer_id = c.id
ORDER BY o.customer_id, c.id;
출력 예시
Merge Join (cost=5000.00..10000.00 rows=100000 width=200) (actual time=5.0..12.0 rows=100000 loops=1)
Merge Cond: (o.customer_id = c.id)
-> Index Scan using orders_customer_id_idx on orders o (cost=0.00..5000.00 rows=100000 width=100)
-> Index Scan using customers_pkey on customers c (cost=0.00..5000.00 rows=50000 width=100)
병합 조인 특징
Merge Cond
는 병합 조건을 의미합니다.- 두 테이블이 정렬된 상태라면 조인 성능이 매우 우수합니다.
4. 조인 알고리즘 비교 및 정리
조인 방식 | 사용 조건 | 장점 | 단점 |
---|---|---|---|
해시 조인 | 등가 조인(=) | 대용량 테이블에서 빠름, 인덱스 필요 없음 | 메모리 사용량 많음, 비등가 조인 불가 |
중첩 루프 조인 | 작은 테이블 또는 인덱스가 있는 경우 | 인덱스 사용 시 빠름, 메모리 사용 적음 | 큰 테이블에서는 매우 비효율적 |
병합 조인 | 정렬된 테이블 조인 | 대용량 데이터에서 효율적 | 정렬 비용이 추가될 수 있음 |
결론
- 작은 테이블 조인 → 중첩 루프 조인(Nested Loop Join)
- 큰 테이블이지만 인덱스 없음 → 해시 조인(Hash Join)
- 정렬된 데이터 조인 → 병합 조인(Merge Join)
조인의 성능을 최적화하려면 EXPLAIN ANALYZE
를 사용하여 실행 계획을 확인하고, 필요에 따라 인덱스 추가, 테이블 정렬, 메모리 조정을 수행해야 합니다.
'Database > PostgreSQL' 카테고리의 다른 글
PostgreSQL 복합 인덱스(Composite Index) 완벽 가이드 (0) | 2025.02.16 |
---|---|
PostgreSQL 성능 튜닝: ANALYZE vs EXPLAIN ANALYZE 차이점과 활용법 (0) | 2025.02.16 |
Dead Tuple (0) | 2025.02.16 |
VACUUM 간단 정리 (0) | 2025.02.16 |