Sangwon
06/10/2026, 9:15 AMRocky
06/10/2026, 9:16 AMFILES() 테이블 함수와 Spark의 MERGE INTO 구문을 혼합해서 사용하려는 시도로 보입니다. 결론부터 말씀드리면, 두 가지 이유로 해당 방식은 현재 불가능합니다.
1. FILES() 함수는 StarRocks 전용입니다
`FILES()`는 StarRocks 엔진이 클라우드 스토리지(MinIO, S3 등)의 파일을 직접 읽고 스키마를 추론하기 위해 제공하는 *StarRocks 전용 SQL 확장*입니다.
* Spark 환경(Spark Iceberg Connector 사용 시)에서는 StarRocks의 FILES() 함수를 인식할 수 없습니다.
_ Spark에서 Parquet 파일을 읽으려면 Spark의 기본 기능을 사용해야 합니다: spark.read.parquet("s3a://...") 또는 SQL에서 SELECT _ FROM parquet.path.
2. StarRocks는 Iceberg 테이블에 대한 `MERGE INTO`를 아직 지원하지 않습니다
StarRocks는 현재(v3.4 기준) Iceberg 테이블(V2)에 대해 INSERT, DELETE, *`UPDATE`*는 지원하지만, MERGE INTO 구문은 아직 지원하지 않습니다.
* `MERGE INTO`는 현재 StarRocks의 *내부 테이블(Primary Key 테이블)*에 대해서만 사용할 수 있습니다.
_ 따라서 StarRocks SQL 내에서 `MERGE INTO target_iceberg USING (SELECT _ FROM FILES(...))`와 같은 쿼리를 실행할 수 없습니다.
──────────
권장 해결 방안
원하시는 작업(MinIO의 Parquet 데이터를 Iceberg 테이블로 Merge/Upsert)을 수행하려면 다음 두 가지 중 하나를 선택해야 합니다.
방법 A: Spark를 사용하여 Merge 수행 (가장 권장)
Spark의 Iceberg 커넥터를 사용하여 Parquet 파일을 읽고 `MERGE INTO`를 실행합니다.
scala
// Spark에서 Parquet 파일을 읽어 뷰로 등록
val sourceDF = spark.read.parquet("<s3a://minio_path/data.parquet>")
sourceDF.createOrReplaceTempView("source_data")
// Iceberg 테이블로 MERGE INTO 실행
spark.sql("""
MERGE INTO iceberg_catalog.db.target_table t
USING source_data s
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
""")
방법 B: StarRocks에서 INSERT OVERWRITE 사용
`MERGE INTO`가 꼭 필요한 것이 아니라 전체 데이터를 갱신하거나 특정 파티션을 교체하는 것이라면, StarRocks에서 FILES() 함수를 활용할 수 있습니다.
sql
-- StarRocks에서 실행
INSERT OVERWRITE iceberg_catalog.db.target_table
SELECT * FROM FILES(
"path" = "s3://...",
"format" = "parquet",
...
);
요약하자면: FILES() 구문은 StarRocks에서만 동작하며, StarRocks는 현재 Iceberg 대상의 `MERGE INTO`를 지원하지 않으므로, Spark를 쓰실 거라면 FILES() 대신 Spark의 데이터 로딩 방식을 사용하셔야 합니다.
• Iceberg Catalog DML 가이드
• FILES() 함수 사용법
References
• data_source/catalog/iceberg/DML.md
• data_source/catalog/iceberg/iceberg_catalog.md
• quick_start/iceberg.md
• data_source/catalog/iceberg/DDL.mdSangwon
06/10/2026, 9:18 AMRocky
06/10/2026, 9:18 AMsql
-- 세션 변수 설정 또는 Hint 사용
SET dynamic_overwrite = true;
INSERT OVERWRITE iceberg_catalog.db.target_table
SELECT * FROM FILES(...);
이 설정을 켜면 소스 데이터(FILES)에 있는 파티션 키 값에 해당하는 파티션만 덮어쓰고, 데이터가 없는 파티션은 건드리지 않습니다.
3. 중복 데이터만 덮어쓰기? (Record-level Upsert 여부)
가장 중요한 부분입니다. `INSERT OVERWRITE`는 *파티션 단위의 교체*이지, 레코드 단위의 업서트(Upsert)가 아닙니다.
* 동작 방식: 특정 파티션에 기존 데이터가 100건 있고, 새로 넣는 데이터가 10건(중복 포함)이라면, 기존 100건을 모두 지우고 새 데이터 10건만 남깁니다.
* 원하시는 결과(중복은 교체, 새 데이터는 추가): 이것은 `MERGE INTO`의 영역입니다. `INSERT OVERWRITE`로 이를 구현하려면 소스 쿼리에서 직접 기존 테이블과 조인하여 "기존 데이터 + 새 데이터"를 합친 결과를 만들어 통째로 파티션에 부어야 합니다.
요약
* 파티션이 다 날아가나요? -> 기본은 그렇지만, `SET dynamic_overwrite = true;`를 쓰면 데이터가 있는 파티션만 교체됩니다.
* 레코드별 중복 처리인가요? -> 아니요. 파티션 내의 기존 데이터를 모두 삭제하고 새 데이터로 갈아끼우는 방식입니다.
따라서 Iceberg 테이블에 대해 정교한 레코드 단위 MERGE 작업이 필요하시다면, 앞서 말씀드린 대로 *Spark*를 사용하시는 것이 현재로서는 가장 확실한 방법입니다.
References
• loading/InsertInto.md
• sql-reference/sql-statements/loading_unloading/INSERT.md
• data_source/catalog/iceberg/DML.md
References
• data_source/catalog/iceberg/DML.md
• loading/InsertInto.md
• sql-reference/sql-statements/loading_unloading/INSERT.md