Skip to content

Commit 7b55598

Browse files
committed
Query Processing Optimizations
1 parent ca33ebc commit 7b55598

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

_posts/2024-09-22-paper_review_presto.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,37 @@ Presto의 자원 관리는 단일 클러스터에서 수백개의 쿼리를 동
169169
- 다만 2018말 기준으로 코디네이터 또는 워커 노드의 실패에 대해 의미있는 내장 내결함성을 갖고 있지 않다. 코디네이터가 실패하면 클러스터를 사용할 수 없고 워커 노드가 실패하면 노드 내 수행되는 모든 쿼리가 실패한다.
170170

171171
# Query Processing Optimizations
172+
173+
## A. Working with the JVM
174+
- Presto는 자바로 구현되었고 Hotspot JVM에서 실행된다.
175+
- 데이터 합축 체크섬 알고리즘 등의 성능에 민감한 코드는 method inlining, loop unrolling 등 JIT 컴파일러 수준의 최적화가 도움이 된다.
176+
- 가비지 컬렉션 알고리즘의 선택은 성능에 극적인 효과를 줄 수 있다. Presto는 G1GC를 사용한다. G1GC는 특정 크기를 초과하는 객체를 잘 다루지 못하기에 Presto는 큰 객체나 버퍼를 할당하는 것을 피하고 필요하면 분할된 배열을 사용한다. 크고 링크가 많은 객체 그래프는 G1의 remembered set 때문에 문제가 된다. 쿼리 실행의 주요 경로에 있는 자료구조는 참조와 객체 카운트를 줄이기 위해 평평한 메모리 배열로 구현되었다. 예를 들어 `HISTOGRAM` 집계는 버킷 키와 카운트를 평평한 배열의 집합과 해시 테이블에 저장하고 각 히스토그램별로 독립적인 객체를 유지하지 않는다.
177+
178+
## B. Code Generation
179+
코드 생성은 JVM 바이트코드를 만든다. 이것은 두가지 형태를 가진다.
180+
1. Expression Evaluation : 쿼리 엔진의 성능은 복잡한 표현을 평가하는 데 달려 있다. Presto는 표현 해석기를 포함하지만 상용에서 사용하기에는 느리다. 때문에 Presto는 상수, 함수 호출, 변수 참조 등를 네이티브하게 다루는 바이트코드를 생성한다.
181+
2. Targeting JIT Optimizer Heuristics : Presto는 몇몇 주요 연산에 대한 바이트코드를 생성한다. 생성기는 다음을 목표한다.
182+
- 엔진이 별도 태스크에서 다른 스플릿 간 스위치한다면 JIT은 일반적인 루프 기반의 구현 최적화에 실패한다. 수집한 정보가 다른 태스크나 쿼리에서 필요없기 때문.
183+
- 단일 태스크 파이프라인의 루프 내에서도 필요없는 루프 언롤링이나 인라인을 수행할 수 있다.
184+
- 바이트코드 생성은 엔진의 중간 결과를 메모리가 아닌 CPU캐시나 레지스터에 저장하는 능력을 향상시킨다.
185+
186+
## C. File Format Features
187+
- Scan 오퍼레이터는 커넥터 API를 호출하고 Page라는 형대로 컬럼 기반 데이터를 받는다. 페이지는 Block의 리스트이며 각 블럭은 컬럼의 플랫 인메모리 표현이다. 플랫 메모리 자료구조는 성능상 이점이 있다. 특히 복합 타입, 포인터 추적, 언박싱, 가상 메서드 호출 등에서
188+
- Presto는 파일 포맷의 커스텀 reader를 전달한다. 이는 파일 헤더나 푸터의 통계(min-max ragne header and Bloom filters)로 데이터 영역을 효과적으로 생략할 수 있다. 또한 커스텀 리더는 특정 형태의 압축 데이터를 블럭으로 직접 변환할 수 있다.
189+
- ![](https://dt5vp8kor0orz.cloudfront.net/deb3b1023aa97d164a291e64032fa3f05d566a58/9-Figure5-1.png)
190+
- 딕셔너리 인코딩 블럭은 low-cardinality 압축시 효과적이다. run-length 인코딩 블럭은 반복되는 데이터를 압축한다. 페이지 간 딕셔너리를 공유하면 메모리 효율적이다. ORC파일의 컬럼은 전체 stripe(수백만row)에 단일 딕셔너리를 사용 가능하다.
191+
192+
## D. Lazy Data Loading
193+
- Presto는 데이터의 지연 구체화를 지원한다. 이는 ORC, Parquet, RCFile등 컬럼 기반의 압축된 파일에 효과적이다. 커넥터는 cell에 실제로 접근할 때 데이터를 읽고 압축풀고 디코딩하는 lazy block을 생성할 수 있다. CPU시간의 대부분이 위 연산에 소요되고 필터는 매우 선택적이기 때문에 컬럼 접근이 잦지 않을 때 매우 효과적이다.
194+
195+
## E. Operating on Compressed Data
196+
- 변환이나 필터를 수행하는 페이지 처리기가 딕셔너리 블럭을 만나면 딕셔너리 내 모든 값을 처리한다(혹은 RLE 블럭의 단일 값). 때문에 전체 딕셔너리는 빠른 루프로 처리된다.
197+
- 블럭 내 row수보다 딕셔너리 값이 많으면 페이지 프로세서는 참조되지 않은 값이 후속 블럭에서 사용될 것이라고 추측한다.
198+
- 조인이나 집계에서 해시 테이블을 생성할 때도 딕셔너리 블럭 구조를 사용한다. 인덱스가 처리될 때 오퍼레이터는 해시 테이블의 위치를 기록해두고 후속 인덱스에서 재사용한다.
199+
- Presto는 또한 실행 중에 중간 압축 결과를 생성한다. 예를 들어 조인 처리기는 효율적이라면 딕셔너리나 RLE 블럭을 생성한다.
200+
- 해시 조인에서 probe측이 해시 테이블의 키를 룩업할때 실제 데이터를 복사하지 않고 값 인덱스를 배열에 기록한다. 오퍼레이터는 인덱스 리스트가 해당 배열인 딕셔너리 블럭을 생성한다. 해당 딕셔너리는 해시 테이블 내 블럭의 참조이다.(암튼 값 인덱스만 써서 복사 없이 조인한다는 뜻)
201+
202+
# Performance
203+
> SKIP
204+
205+
# Engineering Lessons

0 commit comments

Comments
 (0)