본문 바로가기

IT & AI

Postgres 분석 쿼리를 300배 앞선 pgrust의 실행 엔진 설계

728x90

Postgres 분석 쿼리를 300배 앞선 pgrust의 실행 엔진 설계

pgrust 쿼리 엔진 최적화 썸네일
pgrust 쿼리 엔진 최적화 썸네일

Postgres 호환 데이터베이스 pgrust 0.2가 쿼리 실행 엔진을 크게 손봤어요. 프로젝트가 공개한 ClickBench 결과에서는 Postgres보다 300배 빠르고, OLTP 벤치마크에서는 30% 앞섰어요. 다만 이 수치는 특정 장비와 설정에서 나온 프로젝트 측 측정값이라 조건을 함께 봐야 해요. 1 2

핵심 요약

구분핵심왜 볼 만한가요
실행 모델한 행씩 넘기는 Volcano 모델의 호출 비용을 배치 처리로 줄였어요쿼리 구조를 유지하면서 CPU가 처리할 작업 단위를 키웠어요
데이터 이동스캔과 집계를 하나로 합쳐 중간 버퍼 복사를 없앴어요계산보다 데이터 이동이 비싸지는 구간을 직접 줄였어요
CPU 활용AArch64 SIMD로 여러 `f64` 값을 한 번에 더했어요축소 실험이 1.3초에서 135ms로 짧아졌어요
적용 범위모든 연산자 조합을 미리 만들 수 없어 JIT가 필요해요빠른 데모와 범용 SQL 엔진 사이의 간격을 보여줘요
주의점부동소수점 합산 순서가 바뀌면 결과가 미세하게 달라질 수 있어요속도뿐 아니라 수치 재현성도 함께 설계해야 해요

1. 행 단위 실행 비용을 배치·융합·SIMD로 줄였어요

Postgres의 실행기는 쿼리 계획에 있는 각 노드가 `next()`를 호출해 한 행씩 주고받는 Volcano 모델을 써요. 구조가 단순하고 새로운 계획 노드를 붙이기 쉽지만, 처리할 행이 많으면 함수 호출도 같은 규모로 늘어요. 런타임에 호출 대상을 정하는 간접 호출이 반복되면 CPU 파이프라인과 컴파일러 최적화도 충분히 활용하기 어려워요. 2

pgrust 개발자는 5억 개의 `float8` 값을 합산하는 축소 실험으로 비용을 나눠 측정했어요. 행 단위 Volcano 구현은 1.3초가 걸렸고, 최대 1,024개 값을 스택 버퍼에 담아 넘기자 480ms로 줄었어요. 호출 횟수를 줄이고 실행 중 별도 메모리 할당을 피한 결과예요.

728x90

다음 병목은 값을 배치 버퍼로 복사하는 작업이었어요. 순차 스캔과 합계를 하나의 노드로 합친 연산자 융합을 적용하자 중간 복사가 사라졌고 실행 시간은 358ms가 됐어요. 마지막으로 AArch64 SIMD 명령을 사용해 여러 `f64` 값을 동시에 더하자 135ms까지 짧아졌어요. 같은 축소 구현 안에서 Volcano 방식보다 9.6배 빠른 결과예요.

프로젝트가 내세운 300배는 이 축소 실험의 9.6배와 다른 숫자예요. 300배는 ClickBench에서 pgrust 전체와 Postgres를 비교한 결과고, 쿼리 엔진 변경 자체가 기여한 폭은 프로젝트 설명 기준 약 10배예요. 두 수치를 분리해서 읽어야 엔진 최적화 효과를 과장하지 않아요. 1

측정 조건도 함께 봐야 해요

원문은 AWS `c8g.4xlarge`의 Graviton4 16 vCPU 환경과 PostgreSQL 18.4를 사용했어요. Postgres의 병렬 쿼리는 껐고, 데이터는 공유 버퍼에 올린 상태에서 5회 실행한 중앙값을 썼어요. Rust 구현은 릴리스 모드로 빌드한 뒤 같은 장비의 단일 프로세스에서 구현별 4회 측정했어요.

단순 Rust 루프와 Postgres 쿼리는 같은 일을 하더라도 내부 경로가 달라요. Postgres에는 잠금, 저장 형식 해석, 튜플 추출 같은 추가 작업이 들어가요. 원문도 이를 동일 조건 비교로 보지 않아요. 축소 실험은 어느 실행기 비용을 줄였는지 설명하는 자료로 보는 편이 맞아요.

범용 SQL에서는 JIT와 정확성 정책이 필요해요

연산자 융합은 자주 쓰는 스캔과 집계 조합에서 효과가 커요. 하지만 조인, 정렬, 서브쿼리까지 포함한 모든 계획 조합을 미리 코드로 만들 수는 없어요. pgrust는 쿼리마다 알맞은 융합 코드를 만드는 JIT 컴파일을 다음 과제로 두고 있어요.

SIMD도 공짜 최적화는 아니에요. 부동소수점 덧셈은 계산 순서에 따라 마지막 비트가 달라질 수 있어요. 여러 값을 병렬로 더하면 순차 합산과 미세하게 다른 결과가 나올 수 있어요. 분석 데이터베이스를 설계할 때는 허용 오차, 재현성, 집계 자료형을 제품 정책으로 정해야 해요.

왜 중요한가요

이 사례는 오래된 데이터베이스가 느리다는 단순한 이야기가 아니에요. 데이터가 RAM에 머무는 비율이 높아지고 NVMe가 빨라지면서, 분석 쿼리의 병목이 디스크 입출력에서 CPU 처리량과 메모리 대역폭으로 옮겨가는 구간이 늘었어요. 실행 엔진이 행을 전달하는 방식과 중간 데이터를 복사하는 횟수가 실제 성능을 크게 좌우해요. 2

데이터베이스를 고르는 팀은 최고 수치보다 워크로드 적합성을 먼저 확인해야 해요. ClickBench 같은 분석 중심 결과가 좋아도 트랜잭션 격리, 확장 기능 호환성, 장애 복구, 운영 도구까지 같은 수준이라는 뜻은 아니에요. pgrust 0.2의 OLTP 결과와 분석 결과가 서로 다른 폭을 보인 점도 이를 잘 드러내요.

직접 검증하려면 실제 테이블 크기와 쿼리 분포를 그대로 둔 별도 벤치마크가 필요해요. 병렬 실행 여부, 데이터 캐시 상태, 동시 접속 수, 숫자 정확성 허용 범위를 기록해야 비교가 의미 있어요. pgrust의 결과는 배치 처리와 연산자 융합, SIMD가 어디서 속도를 만드는지 보여주는 좋은 구현 사례지만, 운영 환경의 결론은 각 팀이 다시 측정해야 해요.

참고 자료

  1. 배치 처리·연산자 융합·SIMD로 Postgres 분석 성능을 300배 높인 pgrust — GeekNews
  2. Rebuilding Postgres for 300x faster analytics: batching, operator fusion, and SIMD — malisper.me
728x90