Polars 2.0
Polars 2.0 출시 — 스트리밍 실행과 디스크 스필 기본 적용
Polars 2.0은 LazyFrame의 collect()에서 스트리밍 엔진을 기본 사용하고, 메모리가 부족하면 디스크에 데이터를 기록하는 out-of-core 처리를 켭니다. SQL 지원과 쿼리 최적화도 강화했으며, TPC-H·TPC-DS 벤치마크에서 대부분의 항목이 가장 빨랐다고 밝혔습니다.
- 주제
AI 요약
Polars 2.0은 SQL 지원, 쿼리 엔진 성능, 대용량 처리 기능을 강화한 주요 버전입니다. 가장 큰 실행 방식 변화는 LazyFrame의 collect()가 기본으로 스트리밍 엔진을 사용한다는 점입니다. 이와 함께 메모리가 부족할 때 디스크를 활용하는 out-of-core 처리도 기본으로 켭니다. 새 Map 자료형과 더 엄격한 타입 검증도 포함했습니다.
SQL과 쿼리 성능
Polars는 SQL을 일급 기능으로 다루기 시작합니다. 최근 몇 달간 SQL 지원 범위를 넓혔고, 조인 순서 재배치, 공통 하위 계획 제거(common-subplan elimination), 동적 조건과 Bloom filter 등 optimizer와 엔진을 개선했습니다.
성능 비교에는 TPC-H와 TPC-DS 데이터를 사용했습니다. Polars SQL을 DuckDB 1.5.6, DuckDB 2.0 alpha(2.0.0.dev2610011535), DataFusion 54.0.0과 비교했습니다. 테스트 머신은 16 vCPU·32GB RAM의 c7a.4xlarge와 192 vCPU·384GB RAM의 c7a.metal입니다. 각 쿼리를 캐시가 따뜻한 상태에서 5회 실행하고, 쿼리별 최단 시간을 합산하는 방식과 기하평균으로 비교했습니다. 각 쿼리는 별도 프로세스에서 실행했으며 제한 시간은 60초였습니다. 벤치마크 데이터는 EBS에 저장했고, 파일 캐시는 엔진이나 벤치마크를 바꿀 때 비웠습니다.
Polars와 DuckDB 두 버전은 모든 쿼리를 완료했습니다. DataFusion은 TPC-DS q72에서 시간 초과가 났고 q67도 한 번 시간 초과됐으며, c7a.4xlarge에서 TPC-H q18 실행 중 메모리가 부족했습니다. 이 쿼리들은 모든 엔진의 결과에서 제외했습니다. Polars 측은 기본 설정에서 벤치마크 한 항목을 제외하고 가장 빨랐다고 보고했습니다. 다만 192개 스레드로 확장할 때 작은 데이터 쿼리에서는 상시 오버헤드가 성능을 떨어뜨렸습니다. Polars를 32개 코어로 제한하면 모든 벤치마크에서 경쟁력 있거나 앞섰다고 밝혔습니다.
데이터 규모가 SF100일 때 16에서 192 vCPU로 늘리면 Polars는 TPC-H에서 3.8배, TPC-DS에서 2.2배 빨라졌습니다. DuckDB 1.5.6은 각각 3.2배와 1.9배, DuckDB 2.0 alpha는 2.2배와 1.5배, DataFusion은 1.7배와 1.0배 향상됐습니다. SF10에서는 Polars 기본 설정이 추가 코어의 이점을 얻지 못했습니다. TPC-H 성능은 같았고 TPC-DS에서는 1.8배 느려졌습니다. 팀은 높은 코어 수에서 작은 쿼리의 오버헤드를 확인했으며, 조인 단계에서 스레드 수 T에 따라 T²개의 파티션을 만드는 점을 원인 사례로 들었습니다. 벤치마크 실행 코드와 원자료는 공개 저장소에 있습니다.
스트리밍과 디스크 스필
LazyFrame에서 collect()를 호출하면 이제 스트리밍 엔진이 기본으로 실행됩니다. 이 엔진은 join, group_by, unpivot 등 일부 연산에서 행 순서를 보장하지 않습니다. 결과 순서가 필요하면 maintain_order=True를 지정해야 합니다. 동작 변화와 API 변경 때문에 메이저 버전 번호를 올렸습니다.
out-of-core 기능은 메모리 사용량이 RAM의 약 80%에 이르면 디스크로 데이터를 내보내기 시작하며, 기본 디스크 사용 한도는 64GB입니다. 현재 sort, window function, 여러 표현식이 지원 대상입니다. 조인과 group_by 지원은 이후 작업으로 남아 있습니다. 작성자는 두 기능이 메모리 사용량이 큰 작업의 안정성을 높인다고 설명합니다.
Map 자료형과 엄격한 오류 처리
Polars는 Apache Arrow의 MapType을 Polars Map dtype으로 직접 지원합니다. 이전에는 Arrow MapType을 key와 value를 담은 Struct의 List로 읽었습니다. 새 자료형에는 고정 키나 다른 열의 값을 이용한 조회, 키 포함 여부 확인, 길이·키·값 추출 같은 사전형 표현식을 제공합니다.
타입과 데이터 불일치는 가능한 한 일찍 오류로 드러내는 방향을 강화했습니다. 암묵적인 변환이나 불일치 처리는 기본 동작으로 감추지 않고, 오류를 빨리 알려 파이프라인 후반에 문제가 드러나는 일을 줄이려는 목적입니다. collect_schema()를 호출하면 데이터를 실제로 처리하지 않고도 쿼리 스키마와 타입을 확인할 수 있습니다. 다만 실제 데이터에 따라 달라지는 오류는 쿼리 계획 단계에서 모두 잡히지 않으며, 이 경우에도 조용히 다른 결과를 내기보다 엄격하게 실패하도록 기본 동작을 조정했습니다.
Hacker News 반응
- @dkgs — DuckDB도 곧 2.0.0을 낸다는데, 우연이겠죠? :)
- @m00dy — 서로 뭘 두고 경쟁하나요?
- @vindex10 — 발표문에 SQL 지원과 성능 개선으로 TPC-H와 TPC-DS에서 Polars가 DataFusion과 DuckDB보다 앞선다고 적혀 있으니, 그쪽 경쟁인 것 같습니다.
- @orlp — 실제로는 아닙니다. 2.0 작업은 오래전부터 계획했습니다. 1.0을 낸 뒤 1.x를 빨리 넘어가겠다고 했지만 생각보다 오래 머물렀습니다. 확인해 보니 2.0 브랜치에 첫 PR들이 들어간 시점은 2026년 6월이었습니다.
- @hnd9q09qk4 — 제가 가장 궁금한 점은 eager와 lazy를 오가면서 생기던 함정이 정리됐는지입니다. 루프 안에 collect()를 실수로 넣어 쿼리 계획이 망가지는 버그를 절반쯤 겪었습니다.
- @sgarland — Polars가 SQL을 지원한다는 걸 오늘 알았습니다. 놀랍네요.
- @dist-epoch — 초기 버전부터 지원했지만 범위가 제한적이었습니다. 이제 DuckDB와 정면으로 경쟁하려는 것 같습니다.
- @efromvt — 로컬 데이터 SQL 분야에서 경쟁이 생기면 모두에게 좋습니다.
- @popularonion — 벤치마크 글을 보고 “A가 B보다 몇 퍼센트 빠르다”고 받아들이면 안 됩니다. 쿼리, 머신, 디스크 설정, 캐시, 스레드 수, 메모리 등에 따라 결과가 크게 달라집니다. 이런 결과는 특정 작업에 맞춘 성능 개선에 집중했고, 이전 버전보다 나아질 것으로 기대한다는 뜻에 가깝습니다.
- @orlp — 쿼리와 머신, 디스크, 캐시, 설정, 스레드 수, RAM을 고르면 결과가 달라질 수 있다는 뜻으로 이해합니다. 각 프로젝트가 자기 벤치마크에서 늘 이기는 이유도 있습니다. 자사 코드는 벤치마크에 맞춰 개선하고, 다른 엔진은 기본 설정으로 한 번 실행하는 식이니까요. 공정하게 하려고 DuckDB 쿼리 생성기와 DataFusion 팀의 데이터 생성기, AWS의 일반적인 머신을 사용하고 기본 설정으로 실행했습니다. Polars만 큰 머신에서 32개 스레드 실행도 추가해 작은 데이터에서 더 나아질 여지를 보여줬습니다.
- @jdefting — 이 벤치마크에서 메모리 사용량 차이도 보고 싶습니다. Polars가 DuckDB보다 메모리를 많이 쓰는 문제를 겪었는데, 스트리밍 엔진이 대부분 해결할 것 같습니다.
- @orlp — 쿼리별 최대 메모리 사용량은 저장소의 results 디렉터리에 있는 원자료에서 확인할 수 있습니다.
- @Centigonal — out-of-core 기능이 정말 좋네요. 예전에는 메모리 문제 때문에 pandas와 polars를 떠나 다른 도구를 써야 했습니다.
- @Kinrany — 요즘 Polars와 DataFusion은 어떤 관계인가요? 두 프로젝트가 하나의 생태계로 합쳐지지 못할 이유가 있나요?
- @esafak — Polars는 DataFusion을 사용하지 않습니다.
- @Kinrany — 직접 기반으로 삼는 게 좋은 생각이 아니더라도 두 프로젝트는 비슷한 점이 많은데, 왜 그런가요?
- @esafak — 이슈에서 Polars 제작자는 의존성을 줄이려는 이유라고 설명했습니다. Polars가 DataFusion crate에 의존하면 필요 없는 복잡성이 생긴다고 합니다.
- @raoulj — SQL에서 asof_join()을 지원하지 않는 것 같습니다. 다른 지원 누락도 있는지 모르겠습니다.
- @orlp — Polars에는 asof join이 있으니 SQL 문법과 연결하는 부분이 아직 없을 수 있습니다. 이슈를 열어 주실 수 있나요?
- @raoulj — Polars의 asof join은 자주 씁니다. 이슈를 열겠습니다.
원문: Polars 블로그 / 번역·요약: Trawling