Trino 482: char/varchar 의미론 수정과 Lakehouse split 제어를 한 번에 가져온 릴리스
왜 이번 릴리스를 봐야 하나
2026년 6월 25일 공개된 Trino 482는 겉으로 보면 SQL 문법이 많이 늘어난 릴리스처럼 보인다. AT LOCAL, MATCH, named argument 같은 문법 추가가 실제로 포함돼 있기 때문이다. 하지만 운영자 관점에서 더 중요한 변화는 다른 곳에 있다.
char/varchar혼합 비교 의미론이 바뀌었다. 공백 패딩에 의존하던 결과가 달라질 수 있다.- fault-tolerant execution(FTE) 경로에서 Alluxio-backed exchange storage가 빠졌다. Lakehouse 커넥터의 Alluxio file system 지원도 함께 정리됐다.
- Hive/Iceberg/Delta Lake 계열에서 Parquet row group, split, footer cache를 다루는 조절점이 더 명시적으로 드러났다.
즉, 이 릴리스는 “SQL이 조금 편해졌다”보다 정확성(correctness), 스풀링 스토리지 구조, 파일 포맷 운영 제어면을 먼저 봐야 한다.
변화가 걸리는 경로
1. char/varchar 혼합 비교가 더 이상 공백 패딩에 숨지 않는다
Trino 482의 가장 위험한 breaking change는 char와 varchar 사이의 암묵적 coercion 방향을 뒤집은 점이다.
공식 타입 문서는 482 기준으로 다음을 명시한다.
CHAR값은VARCHAR로 암묵 변환될 때 trailing space가 제거된다.CHAR와VARCHAR를 비교하면 이제VARCHAR의미론을 따른다.- 따라서
CHAR 'a' = VARCHAR 'a '는false다. CHAR끼리의 비교만 기존처럼 blank-padded semantics를 유지한다.
즉, 고정 길이 컬럼을 많이 쓰는 레거시 스키마에서 가장 주의해야 할 것은 “값은 같아 보이는데 사실 공백이 달라서 결과가 바뀌는” 경우다.
SELECT CAST('Test' AS varchar(20)) = CAST('Test ' AS varchar(25)); -- false
SELECT CAST('Test' AS char(20)) = CAST('Test ' AS char(25)); -- true
SELECT CHAR 'a' = VARCHAR 'a '; -- false (482 기준)이 변화는 단순한 표현식 수준에 머물지 않는다.
JOIN에서 고정 길이 코드 테이블과 가변 문자열 입력을 맞물릴 때 cardinality가 달라질 수 있다.GROUP BY,DISTINCT, equality filter 결과가 바뀔 수 있다.- MySQL, SQL Server 커넥터 쪽 release note도 이 변화의 여파를 따로 언급한다. equality /
INpredicate는 trailing space가 다른 값을 잘못 같은 값으로 보던 문제를 바로잡았고, 반대로 inequality / range predicate는 더 이상 pushdown하지 않는다.
특히 SQL Server 커넥터는 더 강하게 영향을 받는다. 릴리스 노트는 DELETE나 UPDATE가 이런 predicate pushdown에 의존하면 실패할 수 있다고 못 박는다. 즉, 정확도는 올라가지만 기존에 “우연히 되던” DML 경로는 깨질 수 있다.
임시 완충 장치
릴리스 노트는 기존 동작을 임시로 되돌리는 설정으로 다음 키를 제공한다.
deprecated.legacy-varchar-to-char-coercion=true이 설정은 업그레이드 직후 회귀를 줄이는 완충 장치로는 유용하지만, 장기 해법은 아니다. 이름 그대로 deprecated 경로이기 때문에 결국 쿼리와 데이터 정규화를 고쳐야 한다.
운영자가 먼저 할 검증
- 고정 길이
CHAR(n)컬럼이 많은 카탈로그를 먼저 식별한다. JOIN,IN,BETWEEN,ORDER BY,GROUP BY가 섞인 대표 쿼리를 골라 481 대비 결과 행 수와 샘플 행을 비교한다.- downstream BI/ETL이 trailing space에 의존해 문자열 정렬·집계를 하고 있었는지 확인한다.
- 필요하면 짧은 기간 동안만 legacy coercion 플래그를 켜고, 그 동안 애플리케이션 쿼리와 데이터 클렌징을 수정한다.
2. FTE 경로에서는 이제 Alluxio를 전제로 생각하면 안 된다
Trino의 fault-tolerant execution은 stage 사이 데이터를 외부 스토리지에 spool해서 worker 중단이나 재시도를 견디는 구조다. 이 경로는 편리하지만, exchange storage에 상당한 I/O 압력을 만든다.
482 릴리스 노트는 여기서 두 가지를 제거했다.
- Alluxio-backed exchange storage 제거
- Delta Lake / Hive / Hudi / Iceberg 커넥터의 Alluxio file system 지원 제거
단, release note는 Alluxio file system cache는 영향받지 않는다고 분리해서 적고 있다. 즉, “Alluxio라는 단어가 완전히 사라졌다”가 아니라 Trino가 직접 책임지는 저장 경로로서의 Alluxio 연동이 정리됐다고 이해하는 편이 정확하다.
공식 FTE 문서는 482 기준으로 exchange manager를 filesystem 또는 hdfs로 설명하고, filesystem 경로 아래에서 S3-compatible, Azure Blob, GCS를 사용하도록 안내한다.
# etc/exchange-manager.properties
exchange-manager.name=filesystem
exchange.base-directories=s3://trino-exchange-a/,s3://trino-exchange-b/
exchange.s3.region=ap-northeast-2
exchange.s3.upload.part-size=16MB
exchange.s3.max-error-retries=10문서가 강조하는 지점도 운영자에게 중요하다.
- exchange storage는 대량 I/O를 받는다.
- 여러 storage location을 둘 수 있다.
- abandoned object를 정리하기 위해 bucket lifecycle rule을 두는 것이 권장된다.
왜 이 변화가 실무적 의미가 큰가
FTE는 보통 배치성 무거운 쿼리, 대규모 ETL, 재시도 가능한 리포트 워크로드에서 켜게 된다. 이런 워크로드는 이미 object storage와 네트워크 대역폭을 많이 사용한다. 그래서 스풀링 경로를 바꾸면 다음이 함께 바뀐다.
- spill / exchange 트래픽이 향하는 대상
- object count 증가 패턴
- lifecycle cleanup 정책
- IAM / credential / endpoint 설정
- 장애 시 orphaned object 정리 방식
따라서 482로 올라가면서 Alluxio-backed exchange를 잃는 팀은 단순히 설정 키만 바꾸는 게 아니라, 스풀링 I/O budget을 어디서 감당할지를 다시 설계해야 한다.
마이그레이션 체크포인트
- 현재
exchange-manager.properties, catalog properties, file-system URI에 Alluxio 관련 설정이 남아 있는지 inventory를 만든다. - FTE 전용 클러스터를 따로 두고 있다면, exchange storage를 production query storage와 분리할지 검토한다.
- 버킷/컨테이너 lifecycle rule로 orphaned exchange object 만료를 설정한다.
- S3-compatible 스토리지를 쓴다면 endpoint, path-style, retry 정책을 명시적으로 점검한다.
- “Alluxio file system cache는 유지, Alluxio-backed exchange는 제거”라는 경계가 팀 문서에 명확히 적혀 있는지 확인한다.
3. Hive/Iceberg/Delta Lake에서 파일 레이아웃과 split 경계가 더 노출된다
482의 세 번째 핵심은 Lakehouse 커넥터가 더 많은 조절점을 드러낸다는 점이다. 이건 성능 최적화 관점에서는 반가운 변화지만, 동시에 운영자가 파일 크기 / row group / split / metadata cache를 더 의식적으로 관리해야 한다는 뜻이기도 하다.
Hive: Parquet split 경계를 별도로 제어
Hive 커넥터에는 hive.parquet.max-split-size가 추가됐다. 공식 문서는 이 값을 Parquet 파일에서 worker 하나에 할당되는 단일 file section의 최대 크기로 설명하고, 기본값을 120MB로 둔다. 설명도 중요하다. 이 값은 “일반적인 Parquet row group보다 약간 작게” 잡혀 row group boundary에 align되도록 설계됐다.
즉, 이제 Hive 쪽에서는:
- 일반 split 정책(
hive.max-split-size) - Parquet 전용 split 정책(
hive.parquet.max-split-size)
를 분리해서 생각해야 한다.
이 변화와 함께 릴리스 노트는 hive.max-initial-splits, hive.max-initial-split-size 제거도 명시한다. 초기 split 개수를 별도로 트릭처럼 만지던 시대에서, 파일 포맷 특성에 맞는 split 경계 자체를 다루는 방향으로 바뀌는 셈이다.
Iceberg: split, footer cache, table property가 더 명시적
Iceberg 커넥터는 482에서 특히 변화가 많다.
iceberg.max-split-sizeiceberg.parquet-footer-cache.typeiceberg.parquet-footer-cache.memory.max-sizetarget_max_file_size,parquet_writer_row_group_size를 table property로 사용data_location을object_store_layout_enabled와 독립적으로 설정 가능
이 변화의 운영적 의미를 풀면 다음과 같다.
#### 1) split 크기는 스캔 병렬성과 skew를 건드린다
공식 문서상 iceberg.max-split-size는 target maximum size of a split이다. hard limit가 아니라 목표값이기 때문에 실제 split은 더 커질 수 있다. 작은 split은 병렬성을 올리지만 scheduling overhead가 늘고, 큰 split은 overhead를 줄이지만 skew와 tail latency를 키울 수 있다.
#### 2) Parquet footer cache는 object storage metadata I/O를 줄이려는 장치다
iceberg.parquet-footer-cache.type=memory는 bounded in-memory cache를 뜻한다. Parquet footer는 row group, statistics, column chunk metadata를 읽기 위해 반복 접근되는 영역이어서, remote object storage에서는 작은 metadata read가 누적 비용이 되기 쉽다. footer cache는 이 구간을 coordinator 쪽 메모리로 당겨온다.
#### 3) write 정책을 session이 아니라 table contract로 남기게 유도한다
공식 문서는 Iceberg table property로 target_max_file_size, parquet_writer_row_group_size를 설명한다. 릴리스 노트는 동시에 동명의 session property 제거를 breaking change로 적는다. 즉, 파일 크기와 row group 크기를 “이번 세션에서 우연히 준 값”이 아니라 테이블 계약의 일부로 옮기는 방향이다.
이건 운영상 꽤 중요하다. Lakehouse에서는 파일 레이아웃이 성능 문제이자 비용 문제인데, 이를 session override에 두면 재현성과 감사 가능성이 떨어진다.
Delta Lake / Hive / Iceberg 공통: row-group row-count limiter
릴리스 노트는 Delta Lake / Hive / Iceberg / Lakehouse 커넥터에 대해 Parquet row group의 row 수 상한을 제어하는 새 설정이 추가됐다고 설명한다. 그런데 여기서 문서 표기 drift가 하나 보인다.
- release note 표기:
parquet.writer.block-row-count,parquet_writer_block_row_count - 482 태그의 file format docs / connector docs / source code 표기:
parquet.writer.row-group-max-row-count,parquet_writer_row_group_max_row_count
실제 482 태그의 ParquetWriterConfig 소스는 @Config("parquet.writer.row-group-max-row-count")를 사용하고, session property 상수도 parquet_writer_row_group_max_row_count로 선언돼 있다.
이 차이는 운영자에게 실전적인 경고다. release note 문구만 복사해서 config를 넣지 말고, 실제 배포 아티팩트가 인식하는 property 이름을 검증해야 한다.
가장 안전한 절차는 다음과 같다.
- 스테이징에서 catalog config validation 로그를 확인한다.
SHOW SESSION LIKE 'parquet_writer_row_group%';로 실제 노출된 session property를 확인한다.- 운영 표준 문서에는 release note 이름이 아니라 배포에서 실제 유효한 키를 적는다.
이 부분은 482에서 가장 유용한 “소스 간 불일치 탐지 포인트” 중 하나다.
4. 이 릴리스는 누구에게 가장 먼저 의미가 있는가
1) CHAR(n)를 오래 끌고 온 레거시 DW / BI 팀
고정 길이 코드 컬럼, SAP/ERP 계열 추출 테이블, 오래된 dimension table이 많다면 482는 성능보다 정확도 회귀 검사가 먼저다.
2) FTE를 적극 쓰는 배치 쿼리 팀
Trino를 대화형 엔진이 아니라 배치성 lakehouse gateway로 쓰고 있다면, exchange storage migration은 release note의 작은 한 줄보다 훨씬 큰 운영 사건이다.
3) Iceberg/Hive 파일 레이아웃을 세밀하게 튜닝하는 팀
작은 파일, row group skew, footer read amplification, split imbalance 때문에 고생하던 팀에게는 482가 실질적 조절면을 더 준다. 다만 knob가 늘어난 만큼 기본값을 그대로 둘지, 테이블 단위 표준을 만들지 결정해야 한다.
5. 업그레이드 전에 바로 실행할 체크리스트
| 점검 영역 | 먼저 볼 것 | 기대 신호 | 문제 시 대응 |
|---|---|---|---|
char/varchar 의미론 | 대표 조인/필터 쿼리 결과 비교 | 481 대비 row count와 샘플 행이 설명 가능하게 변함 | 일시적으로 legacy coercion 사용, 쿼리와 데이터 정규화 수정 |
| MySQL / SQL Server pushdown | equality, IN, range predicate 실행 계획 | equality는 정확도 개선, range는 pushdown 축소가 관찰됨 | DML 실패 경로 식별, predicate 재작성 |
| FTE exchange storage | exchange-manager.properties, URI inventory | Alluxio 전제 제거, S3/Azure/GCS/HDFS로 명시적 정리 | 스풀링 스토리지 migration, lifecycle rule 추가 |
| Hive split tuning | Parquet large file scan latency / task count | row group boundary와 split이 더 잘 맞음 | hive.parquet.max-split-size 재조정 |
| Iceberg metadata I/O | coordinator memory / object-store HEAD·GET 패턴 | footer cache로 metadata read 감소 | cache size 축소 또는 비활성화 |
| Parquet row-group row count knob | config validation / SHOW SESSION | 실제 유효 property 이름 확인 | 문서 갱신, release note 이름 복붙 금지 |
정리
Trino 482를 “SQL 문법 확장 릴리스”로만 보면 절반만 본 셈이다. 실제 운영자에게 더 중요한 것은 다음 세 가지다.
- 문자열 비교의 정확도 기준이 달라졌다. trailing space를 묵인하던 mixed comparison이 더 엄격해진다.
- FTE 스풀링 경로에서 Alluxio 기반 전제가 사라졌다. exchange storage 설계를 다시 확인해야 한다.
- Lakehouse 파일 레이아웃 제어가 더 구체적이 됐다. split, footer cache, table property를 명시적으로 운영할 수 있다.
따라서 482 업그레이드의 첫 단계는 “새 문법을 써볼까?”가 아니라 다음 순서가 맞다.
CHAR/VARCHAR혼합 비교 회귀 테스트- FTE / Alluxio 의존성 inventory
- Hive/Iceberg 파일 레이아웃·split 표준 재점검
이 세 가지를 끝낸 뒤에야, 482는 비로소 안전하게 쓸 수 있는 query engine 릴리스가 된다.
References
- https://trino.io/docs/current/release/release-482.html
- https://trino.io/docs/current/language/types.html
- https://trino.io/docs/current/functions/comparison.html
- https://trino.io/docs/current/installation/query-resiliency.html
- https://trino.io/docs/current/admin/fault-tolerant-execution.html
- https://trino.io/docs/current/connector/hive.html
- https://trino.io/docs/current/connector/iceberg.html
- https://trino.io/docs/current/object-storage/file-formats.html
- https://trino.io/docs/current/connector/delta-lake.html
- https://github.com/trinodb/trino/blob/482/plugin/trino-hive/src/main/java/io/trino/plugin/hive/parquet/ParquetWriterConfig.java
- https://github.com/trinodb/trino/blob/482/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveSessionProperties.java