병렬 쿼리

병렬 쿼리 (Parallel Query)

이번 페이지에서는 PostgreSQL의 병렬 쿼리(parallel query) — 15장 전체의 개요를 함께 살펴볼게요. "쿼리 플랜이 여러 CPU를 활용해서 응답을 더 빨리 내놓게 하는 기능"이 어떻게 동작하고, 언제 쓸 수 있는지, 어떤 주의점이 있는지 옆에서 차근차근 설명해 드릴게요.

출처: PostgreSQL 공식 문서 — parallel-query

병렬 쿼리란 무엇인가 (What parallel query is)

PostgreSQL은 쿼리를 더 빨리 처리하기 위해 여러 CPU를 활용할 수 있는 쿼리 플랜을 고안할 수 있어요. 이 기능을 **병렬 쿼리(parallel query)**라고 해요.

많은 쿼리는 병렬 쿼리의 혜택을 받지 못해요. 그 이유는 현재 구현의 한계 때문이거나, 직렬(serial) 쿼리 플랜보다 더 빠른 쿼리 플랜이 상상할 수 없기 때문이에요. 하지만 혜택을 받을 수 있는 쿼리의 경우, 병렬 쿼리로 얻는 속도 향상은 매우 크게 나타나요.

  • 많은 쿼리가 병렬 쿼리를 사용할 때 두 배 이상 빠르게 실행돼요.
  • 어떤 쿼리는 네 배 또는 그 이상 빠르게 실행될 수 있어요.
  • 대량의 데이터를 다루지만 사용자에게는 적은 수의 행만 반환하는 쿼리가 보통 가장 큰 혜택을 받아요.

이 장에서는 병렬 쿼리가 어떻게 동작하는지, 어떤 상황에서 사용할 수 있는지에 대한 세부 사항을 설명해서, 병렬 쿼리를 활용하려는 사용자가 무엇을 기대할 수 있을지 이해할 수 있게 해줘요.

병렬 쿼리가 어떻게 동작하는지 (15.1 How Parallel Query Works)

옵티마이저가 특정 쿼리에 대해 병렬 쿼리가 가장 빠른 실행 전략이라고 판단하면, Gather 또는 Gather Merge 노드를 포함한 쿼리 플랜을 만들어요. 간단한 예시는 다음과 같아요.

EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%';

어떤 경우든 Gather 또는 Gather Merge 노드는 정확히 하나의 자식 플랜을 가져요. 그것이 병렬로 실행될 플랜의 부분이죠. GatherGather Merge 노드가 플랜 트리의 맨 위에 있으면 전체 쿼리가 병렬로 실행돼요.

EXPLAIN으로 플래너가 선택한 워커(worker) 수를 볼 수 있어요. 쿼리 실행 중 Gather 노드에 도달하면, 사용자 세션을 구현하는 프로세스는 워커 수만큼 **백그라운드 워커 프로세스(background worker process)**를 요청해요.

병렬 쿼리를 언제 쓸 수 있나 (15.2 When Can Parallel Query Be Used?)

어떤 상황에서도 병렬 쿼리 플랜을 생성하지 못하게 하는 설정이 몇 가지 있어요. 병렬 쿼리 플랜이 전혀 생성되려면 다음 설정이 지시대로 구성돼야 해요.

  • max_parallel_workers_per_gather0보다 큰 값으로 설정돼야 해요.
  • 시스템이 단일 사용자 모드(single-user mode)로 실행 중이면 안 돼요. 그 상황에서는 전체 데이터베이스 시스템이 단일 프로세스로 실행되므로 백그라운드 워커를 쓸 수 없으니까요.

병렬 플랜 (15.3 Parallel Plans)

각 워커가 플랜의 병렬 부분을 끝까지 실행하므로, 일반 쿼리 플랜을 그대로 여러 워커로 실행하는 것은 불가능해요. 각 워커가 출력 결과 집합의 전체 복사본을 만들게 되고, 그러면 쿼리가 제대로 실행되지 않으니까요.

병렬 스캔 (Parallel Scans): 현재 지원되는 병렬 인식 테이블 스캔 유형이 있어요. 병렬 순차 스캔(parallel sequential scan)에서는 테이블의 블록이 범위로 나뉘어 협력하는 프로세스들 사이에 공유돼요. 각 워커 프로세스는 주어진 블록 범위의 스캔을 완료한 다음 추가 범위를 요청해요.

병렬 조인 (Parallel Joins): 조인도 병렬로 수행될 수 있어요. 병렬 집계 (Parallel Aggregation): 집계도 병렬로 수행돼요. 병렬 Append (Parallel Append): 파티션 테이블 처리에도 사용돼요.

병렬 안전성 (15.4 Parallel Safety)

플래너는 쿼리에 관여하는 연산을 병렬 안전(parallel safe), 병렬 제한(parallel restricted), 병렬 불안전(parallel unsafe) 중 하나로 분류해요.

  • 병렬 안전(parallel safe): 병렬 쿼리의 사용과 충돌하지 않는 연산.
  • 병렬 제한(parallel restricted): 병렬 워커에서 실행될 수 없지만, 병렬 쿼리 중 리더(leader)에서 실행될 수 있는 연산.
  • 병렬 불안전(parallel unsafe): 병렬 쿼리와 함께 실행될 수 없는 연산.

항상 병렬 제한인 연산의 예로는 공통 테이블 표현식(CTE) 스캔이 있어요. 함수와 집계에 대한 병렬 라벨링 규칙도 이 절에 자세히 나와 있어요.

더 알아보기 (Learn more)