쿼리 플랜
쿼리 플랜
어떤 lazy 쿼리든 Polars는 두 가지 플랜을 동시에 갖고 있어요. 하나는 우리가 코드로 작성한 그대로의 단계를 담은 비최적화 플랜(non-optimized plan)이고, 다른 하나는 쿼리 옵티마이저가 변경을 적용한 최적화 플랜(optimized plan)입니다. 이 둘을 시각화하거나 텍스트로 출력해 이해할 수 있어요.
출처: 공식문서
아래 쿼리를 예로 들어 설명해 볼게요.
q1 = (
pl.scan_csv("docs/assets/data/reddit.csv")
.with_columns(pl.col("name").str.to_uppercase())
.filter(pl.col("comment_karma") > 0)
)
비최적화 쿼리 플랜
Graphviz 시각화
쿼리 플랜을 시각화하려면 Graphviz를 설치하고 PATH에 추가해야 합니다. 먼저 optimized=False로 설정해 비최적화 플랜을 그려볼게요.
q1.show_graph(plan_stage="ir", optimized=False)
쿼리 플랜 시각화는 아래에서 위로 읽어야 해요. 시각화에서:
- 각 박스는 쿼리 플랜의 한 단계(stage)를 뜻합니다.
sigma는SELECTION을 뜻하며 필터 조건을 나타냅니다.pi는PROJECTION을 뜻하며 컬럼의 부분 집합을 고르는 것을 나타냅니다.
텍스트로 출력된 쿼리 플랜
비최적화 플랜은 explain(optimized=False)로도 출력할 수 있어요.
q1.explain(optimized=False)
FILTER [(col("comment_karma")) > (0)] FROM WITH_COLUMNS:
[col("name").str.uppercase()]
CSV SCAN data/reddit.csv
PROJECT */6 COLUMNS
출력된 플랜 역시 아래에서 위로 읽습니다. 이 비최적화 플랜은 대략 다음과 같은 일을 뜻해요.
data/reddit.csv파일을 읽는다.- 6개 컬럼을 모두 읽는다 (
PROJECT */6 COLUMNS의*와일드카드는 모든 컬럼을 가져오라는 뜻). name컬럼을 대문자로 변환한다.comment_karma컬럼에 필터를 적용한다.
최적화 쿼리 플랜
이제 show_graph로 최적화된 플랜을 시각화해 볼게요.
q1.show_graph(plan_stage="ir")
streaming 엔진을 쓸 때는 plan_type="streaming"(기본값)으로 설정해 물리 플랜(physical plan)도 시각화할 수 있어요.
q1.show_graph(plan_stage="physical")
최적화된 플랜은 explain으로도 출력할 수 있습니다.
q1.explain()
WITH_COLUMNS:
[col("name").str.uppercase()]
CSV SCAN data/reddit.csv
PROJECT */6 COLUMNS
SELECTION: [(col("comment_karma")) > (0)]
최적화된 플랜은 이런 일을 합니다.
- Reddit CSV에서 데이터를 읽는다.
- CSV를 한 줄씩 읽는 동안
comment_karma컬럼에 필터를 적용한다. name컬럼을 대문자로 변환한다.
이 경우 쿼리 옵티마이저는 파일 전체를 메모리에 읽어들인 뒤 필터를 거는 대신, 디스크에서 CSV를 읽는 동안 필터를 적용할 수 있다는 점을 파악했어요. 이 최적화를 Predicate Pushdown이라고 부릅니다.