81% 빠른 쿼리 플랜 — 4B 모델이 Postgres를 이긴 조건
81% 빠른 쿼리 플랜 — 4B 모델이 Postgres를 이긴 조건
이것은 학습된 옵티마이저의 승리인가, 아니면 실행 측정을 동반한 탐색의 승리인가?
도입
2026년 9월 16일, Rohan Bansal의 글 「Training a 4B model to produce 81% faster query plans than Postgres」가 해커뉴스에서 702점을 받았다. 부제는 「Qwen이 에이전틱 강화학습으로 쿼리 최적화를 배우게 하는 법」이다. 작성자는 Recurse Center에서 안식 기간을 보내며 이 실험을 했고, 코드는 GitHub의 polyphilz/qorl 저장소에 공개했다.
요지는 이렇다. 4B 규모의 오픈 웨이트 모델에 Postgres의 플래너 통계와 플랜을 조회하는 도구를 쥐여 주고, pg_hint_plan 힌트로 플랜을 바꾸는 후보를 제출하게 한다. 처음에는 113개 쿼리 중 99개에서 유효한 플랜조차 못 내던 모델이, GPT-6 Astra의 궤적을 증류한 SFT와 이어진 강화학습을 거쳐 Join Order Benchmark(JOB)에서 기하평균 1.81배의 속도 향상을 냈다는 것이다. 총비용은 약 1,200달러였다.
제목의 숫자는 강렬하다. 그런데 기사를 끝까지 읽으면, 그 1.81배는 상당히 구체적인 조건 아래에서 나온 값이다. 이 글은 그 조건을 하나씩 풀고, 학습된 쿼리 최적화라는 오래된 연구 흐름 속에서 이 실험이 어디에 서 있는지, 그리고 실무자가 평균 속도 향상보다 먼저 물어야 할 것이 무엇인지를 살핀다.
현상 분석 — 1.81배는 어디서 나왔나
먼저 기사가 정의한 문제부터 보자. 쿼리 옵티마이저의 핵심 난제는 조인 순서이고, 기사는 이것이 NP-난해라는 1984년 Ibaraki와 Kameda의 결과를 인용한다. 테이블 세 개짜리 조인만 해도 조인 트리, 입력 방향, 조인 알고리즘, 스캔 방식을 곱하면 4,608가지 실행 방법이 나오고, 열두 개 테이블이면 경우의 수는 천문학적으로 불어난다. Postgres는 이를 동적 계획법으로 가지치기하고, 12개 이상의 조인에는 유전 알고리즘을 쓴다고 기사는 설명한다.
더 근본적인 문제는 카디널리티 추정이다. 플래너는 실제로 조인을 돌려 행 수를 셀 수 없으므로 pg_statistic의 빈도와 히스토그램으로 추정한다. 조인에서는 한 테이블의 값 분포가 다른 테이블에도 균일하게 적용된다고 가정하는데, 이 가정이 깨지면 초기 조인의 오차가 트리 전체로 번진다. 기사의 예에서 일본 회사가 전체 회사의 5%지만 영화의 50%를 냈다면, 플래너가 고른 순서가 실제로는 더 나쁜 순서가 된다.
작성자가 선택한 문제 설정은 영리하다. 그는 모델로 더 나은 카디널리티 추정기를 만드는 방향을 일찍 버렸다. 수십 년의 추정 연구와 싸워야 하고, 추론 지연만으로도 Postgres의 초고속 플래너를 따라잡을 수 없다는 판단이다. 대신 같은 분석 쿼리가 수천 번 반복 실행되는 워크로드를 겨냥했다. 학습과 탐색에 해당 쿼리를 수십에서 수백 번 실행하는 비용이 들더라도, 반복 실행 전체로 상각하면 이득이라는 논리다. 일회성 쿼리에서 Postgres를 이기는 것이 목표가 아니라는 점을 기사는 명시한다.
이제 숫자를 보자. 최종 1,200회 업데이트 RL 체크포인트를 JOB 113개 쿼리에 대해 쿼리당 세 번 실행했을 때, 기사의 표는 세 가지 선택 방식을 나란히 보여 준다.
- 모델이 각 궤적에서 스스로 고른 후보: 339개 궤적 기준 기하평균 1.40배, 총 워크로드 1.24배, 개선 119건, 회귀 7건
- 각 궤적 안에서 예비 측정값이 가장 좋은 후보(1.05배 초과일 때만, 아니면 기본 플랜): 1.44배, 1.29배, 개선 129건, 회귀 1건
- 세 궤적 전체, 즉 최대 15개 후보 중 예비 측정값이 가장 좋은 것: 113개 쿼리 기준 1.81배, 1.81배, 개선 68건, 회귀 0건
제목의 81%는 세 번째 줄이다. 결론부의 「총 지연 44.7% 감소」도 같은 줄에서 나온 값이고, 기사는 각주로 이것이 쿼리당 세 번 시도한 best-of-15 측정이라고 밝힌다. 한 번의 실행, 모델 자신의 선택으로 보면 숫자는 1.40배다. 쿼리당 한 궤적으로 평가한 1,200회 체크포인트의 결과는 1.41배, 회귀 2건이었다.
측정 환경도 짚어 둬야 한다. 데이터는 디스크상 8.5GB의 IMDb 일부이고, Postgres 컨테이너 네 개가 각각 코어 4개와 메모리 8GB를 받았다. 작성자는 측정 잡음을 줄이려고 shared_buffers를 128MB에서 2GB로 올렸고, 그러자 중앙값 쿼리의 작업 집합이 Postgres 자체 캐시에 완전히 상주하게 되었다. 각 쿼리는 버퍼 카운터가 안정될 때까지 예열한 뒤 측정했다. 다시 말해 이 결과는 메모리에 올라간 읽기 전용 분석 쿼리, 예열된 캐시라는 조건 위의 값이다.
심층 분석 — 평균이 가리는 것들
1.81배를 해석하는 열쇠는 두 가지 설계 선택에 있다. 하나는 최종 선택이 실행 측정에 기반한다는 점이고, 다른 하나는 점수가 클리핑된 기하평균이라는 점이다.
첫째, best-of-15의 「회귀 0건」은 모델의 판단력이라기보다 측정 필터의 성질에 가깝다. 각 후보는 한 번 예열하고 한 번 측정한 예비 값을 받고, 1.05배를 넘지 못하면 기본 플랜으로 되돌아간다. 실제로 실행해서 빨랐던 것만 남기는 구조이므로, 회귀가 걸러지는 것은 당연한 귀결이다. 모델 자신의 선택 줄에서 339건 중 7건의 회귀가 있었다는 사실이 이를 뒷받침한다. 정리하면 이 시스템의 실제 단위는 「모델」이 아니라 「모델이 후보를 내고, 데이터베이스가 그것을 실행해 채점하는 루프」다.
둘째, 점수 공식이다. 기사는 최종 측정에서 후보와 기본 플랜을 번갈아 세 쌍 실행하고, 각 중앙값의 비율을 0.1배에서 10배 사이로 클리핑한다. 작성자는 극단적인 개선이나 회귀가 기하평균을 좌우하지 않도록 한 장치라고 설명한다. 학습 신호로서는 합리적이지만, 운영 관점에서 읽으면 의미가 달라진다. 어떤 쿼리가 50배 느려져도 점수상으로는 10배 느려진 것으로 기록된다. 기하평균은 또 쿼리마다 같은 가중치를 주므로, 5분짜리 쿼리의 절반 단축과 25초짜리 쿼리의 두 배 악화가 상쇄된다는 것을 기사 스스로 예로 든다. 작성자가 총 워크로드 속도 향상을 함께 보고한 이유가 이것이다.
꼬리 지연의 관점에서 가장 위험한 것은 평균이 아니라 최악의 경우다. 바닐라 4B 모델의 평가에서 유효했던 새로운 플랜 여섯 개 중 다섯 개는 1.02배에서 1.30배의 개선이었지만, 하나는 0.05배, 즉 약 20배 느렸다. 학습이 이런 꼬리를 얼마나 줄였는지는 회귀 건수로는 보이지만, 회귀의 크기 분포는 기사의 표에 나오지 않는다.
이 문제는 학습된 쿼리 최적화 연구가 오래전부터 씨름해 온 지점이다. 2019년의 Neo는 심층 신경망으로 실행 계획을 직접 생성하는 학습형 옵티마이저였고, PostgreSQL 같은 단순한 옵티마이저로 부트스트랩해도 상용 옵티마이저와 비슷한 성능에 이를 수 있다고 초록에서 밝힌다. 이듬해의 Bao는 방향을 바꿨다. Bao의 초록은 기존 학습형 접근이 학습 오버헤드, 변화에 대한 적응 불능, 나쁜 꼬리 성능 때문에 실용적 이득이 적었다고 진단하고, 플랜을 직접 만드는 대신 기존 옵티마이저에 쿼리별 힌트를 주는 방식을 택했다. 트리 합성곱 신경망과 Thompson 샘플링을 결합해, 꼬리 지연을 포함한 종단 간 실행 성능을 개선했다는 것이 그 주장이다.
이번 실험은 구조적으로 Bao의 후손이다. 기존 옵티마이저를 대체하지 않고 pg_hint_plan 힌트로 조종한다. 작성자도 다음 단계로 Bao 스타일의 구조화된 힌트 탐색이 4B 모델보다 효과적인지 비교하고 싶다고 적었다. 다른 점은 힌트를 고르는 주체가 작은 분류기가 아니라 도구를 호출하는 언어 모델 에이전트라는 것이다. 그리고 이 차이가 바로 해커뉴스 논쟁의 중심이었다.
해커뉴스 반응은 크게 세 갈래였다. 첫째는 측정 조건에 대한 의문이다. 한 이용자는 메모리에 다 들어가는 8GB 데이터셋, 그보다 작게 제한된 shared_buffers, 측정 전 예열, 읽기 전용 SELECT라는 조건을 나열하며, 더 큰 규모와 현실적인 OLTP 워크로드에서도 이 플랜이 Postgres의 휴리스틱보다 나을지는 말하기 어렵다고 적었다(직접 인용은 아니고, 코멘트의 요지를 요약, @refibrillator). 다른 이용자는 모델이 즐겨 쓴 설정 중 random_page_cost=1.1이 있다는 점을 짚었다. 기본 설정에서 이 값이 맞지 않으면 회전식 디스크가 아닌 환경에서 플래너가 나쁜 플랜을 고를 수 있으므로, 그것만으로 차이의 상당 부분이 설명될 수 있다는 의심이다(직접 인용은 아니고, 코멘트의 요지를 요약, @zacmps). 기사는 shared_buffers와 work_mem 조정만 언급하고 random_page_cost를 기본 플랜 쪽에서 조정했다는 서술은 없다. 이 의심은 기사 안에서 반박되지 않은 채 남아 있다.
둘째는 비용 회계다. 한 이용자는 약 95시간의 H100 대여와 API 비용이 벤치마크 수치에 포함되지 않았을 것이라 짚고, 몇 시간씩 모델을 다시 갱신해야 한다면 감당할 수 있느냐고 물었다(직접 인용은 아니고, 코멘트의 요지를 요약, @Someone). 또 다른 이용자는 실시간 플래너의 진짜 제약은 플래닝 시간과 실행 시간의 합을 살아 있는 통계 위에서 줄이는 것인데, 이 프로젝트는 그 어느 쪽도 다루지 않는다고 비판했다(직접 인용은 아니고, 코멘트의 요지를 요약, @perrygeo). 다만 이것은 작성자가 처음부터 반복 실행되는 쿼리로 범위를 좁혔다는 점을 고려하면 절반만 유효한 비판이다.
셋째는 도구 선택이다. 왜 하필 언어 모델이냐는 질문이 여러 번 나왔다. 한 이용자는 SQL과 플랜 힌트라는 작고 제약된 언어 사이의 사상을 배우는 데 방대한 텍스트로 학습된 모델이 왜 필요하냐며, 실제 데이터의 특징을 숫자로 넣는 훨씬 작은 신경망이 맞지 않느냐고 물었다(직접 인용은 아니고, 코멘트의 요지를 요약, @topaz0). 힌트가 필요해지는 대부분의 경우는 통계가 틀렸기 때문이며, 힌트는 문제를 덮을 뿐이고 데이터 모양이 바뀌면 역효과를 낼 수 있다는 DBA 관점의 지적도 있었다(직접 인용은 아니고, 코멘트의 요지를 요약, @sgarland).
전망과 시사점
이 실험이 실제로 증명한 것은 무엇인가. 기사의 결론은 「기업은 데이터를 갖고 있고, RL 환경을 만들어 작은 오픈 웨이트 모델을 니치한 도메인 과제에 학습시키는 것은 적은 비용으로 가능하다」는 가설이다. 이 가설에 대해서는 실험이 꽤 설득력 있는 증거다. 하네스조차 이해하지 못하던 4B 모델이 1,200달러 남짓으로 유효 후보율 101/113에 이르렀고, 그 과정의 시행착오, 즉 가혹한 무효 패널티 때문에 모델이 기본 플랜만 반복하게 된 일, 일반 GRPO가 그룹 평균보다 덜 나쁜 롤아웃을 강화해 버린 일, 검증 손실이 평평한데도 행동이 바뀐 일이 모두 기록되어 있다.
측정 공학에 관한 부분도 그 자체로 가치가 있다. 작성자는 job-13b라는 쿼리의 20회 실행이 186-204ms와 227-253ms 두 덩어리로 갈리는 것을 발견했고, 세 쌍 중앙값 방식에서는 실제로 동일한 플랜이 가짜 개선이나 악화로 판정될 수 있음을 계산했다. 그래서 변동계수 대신 「보상이 속는 비율」을 직접 최소화 목표로 삼았다. shared_buffers 128MB에서 평균 무작동 오류율은 5.0-5.4%였고, 2GB에서는 1.2-1.8%로 떨어졌다. 실행 시간을 보상으로 쓰는 모든 시스템이 빌려 갈 만한 방법론이다.
반면 「Postgres보다 81% 빠른 쿼리 플래너」라는 독해는 이 실험이 증명하지 않는다. 실무에 옮긴다면 다음 질문들이 먼저다.
- 비교 기준선은 튜닝된 Postgres인가. random_page_cost, 통계 대상 확장, 인덱스 설계를 먼저 손본 기본 플랜과 비교해야 모델의 순수 기여가 보인다.
- 회귀의 크기 분포는 어떤가. 회귀 건수뿐 아니라 최악 쿼리가 몇 배 느려졌는지, 클리핑 이전 값으로 봐야 한다.
- 데이터가 바뀌면 무엇이 일어나는가. 힌트는 플랜을 고정한다. 데이터 분포가 이동하면 오늘의 최적 힌트가 내일의 회귀가 된다. 해커뉴스에서 한 이용자가 그린 「LLM 플래너가 이번엔 인덱스를 놓쳐 프로덕션 DB가 멈췄다」는 장면에, 다른 이용자는 「LLM」을 빼고 그냥 「쿼리 플래너」라고 해도 똑같이 성립한다고 답했다(직접 인용은 아니고, 코멘트의 요지를 요약, @2001zhaozhao, @malisper). 맞는 말이지만, 그렇다면 필요한 것은 더 똑똑한 생성기보다 플랜 변경을 감지하고 되돌리는 운영 장치다.
- 측정 루프를 운영 환경에서 돌릴 수 있는가. 이 시스템의 성능은 후보를 실제로 실행해 보는 데서 나온다. 프로덕션 복제본에서 자주 쓰이는 무거운 쿼리를 대상으로 돌려 보는 것은 가능하다는 의견도 있었다(직접 인용은 아니고, 코멘트의 요지를 요약, @dnautics).
현실적인 그림은 이렇다. 범용 쿼리 플래너를 언어 모델로 대체하는 미래는 이 실험이 그리지 않는다. 대신 정기 실행되는 무거운 분석 쿼리 목록을 오프라인에서 탐색해, 실측으로 검증된 힌트를 저장하고, 플랜 변화를 감시하는 「오프라인 플랜 튜너」라는 좁은 제품은 충분히 그려진다. 실제로 해커뉴스에는 그런 제품이 있느냐는 질문도 올라왔다(직접 인용은 아니고, 코멘트의 요지를 요약, @ashley95). 그 제품의 핵심 경쟁력은 모델 크기가 아니라 측정 하네스의 신뢰성일 것이다.
결론
1.81배라는 숫자는 거짓이 아니다. 다만 그것은 「4B 모델이 Postgres보다 빠른 플랜을 낸다」가 아니라 「4B 모델이 쿼리당 최대 15개 후보를 내고, 그중 실제로 실행해서 빨랐던 것만 고르면, 메모리에 올라간 8.5GB IMDb의 JOB 113개 쿼리에서 클리핑된 기하평균 1.81배가 나온다」를 뜻한다. 모델 자신의 단일 선택은 1.40배였고, 그때는 회귀가 7건 있었다.
이 구분이 중요한 이유는 꼬리 때문이다. 쿼리 옵티마이저가 사람을 깨우는 것은 평균이 1.4배일 때가 아니라 한 쿼리가 20배 느려질 때다. Bao가 2020년에 꼬리 성능을 학습형 최적화의 실패 원인으로 꼽은 것도, 이번 실험의 회귀 0건이 측정 필터에서 나온 것도 같은 이야기를 한다. 안전성은 생성기가 아니라 검증 루프에서 온다.
당신의 데이터베이스에서 가장 비싼 쿼리 열 개를 떠올려 보라. 그 쿼리들의 플랜이 바뀌었을 때 그것을 감지하는 장치가 있는가. 없다면, 어떤 플래너를 쓰든 다음 회귀는 평균 속에 묻혀서 도착할 것이다.
출처: