사용자 정의 JDBC 연결과 수집 최적화
사용자 정의 JDBC 소스는 관계형 데이터베이스와 데이터 웨어하우스에 드라이버로 연결하고, 추출 정의의 SQL 질의로 Foundry에 가져올 데이터를 정합니다. 증분 상태를 사용하면 이전 실행 이후의 자료만 읽을 수 있습니다.
Data Connection의 +New Source에서 먼저 BigQuery, PostgreSQL 같은 전용 소스가 있는지 확인합니다. 해당 유형이 없으면 JDBC를 선택합니다.
기본 연결 항목
| 항목 | 필수 여부 | 의미 |
|---|---|---|
URL | 필수 | 대상 드라이버의 JDBC 연결 URL입니다. |
Driver class | 필수 | 데이터베이스 연결에 사용할 드라이버 클래스입니다. 실행 시 classpath에 있어야 합니다. |
Credentials | 필수 | JDBC 사용자 이름과 비밀번호입니다. |
JDBC properties | 선택 | 연결 동작을 설정하는 속성 이름과 값입니다. |
Advanced Options | 선택 | 출력 형식과 수집 동작을 재정의합니다. |
JDBC 연결 기능이 있는 실행 환경이라도 대상 시스템의 드라이버는 별도로 제공해야 합니다. 드라이버 클래스 이름과 실제 업로드한 드라이버가 일치해야 합니다.
드라이버 업로드
Foundry 워커에서는 Palantir 서명이 없는 드라이버도 업로드할 수 있습니다. 대상 시스템이 제공하는 드라이버를 받아 소스 설정에서 업로드합니다.
기존 에이전트 워커
에이전트 워커는 Legacy 방식입니다. 기존 소스에 드라이버를 수동 추가하면 이미 설치된 드라이버와 classpath 충돌이 생길 수 있어 가능하면 Foundry 제공 드라이버를 사용합니다.
에이전트에 업로드할 드라이버에는 Palantir 서명이 필요합니다. 서명하지 않은 드라이버를 올리면 에이전트가 시작하지 못하므로 Palantir 지원에서 서명된 드라이버를 준비합니다.
- 에이전트 개요의 Agent settings를 엽니다.
- JDBC Drivers에서 Edit를 선택합니다.
- 오른쪽 목록에 드라이버가 없으면 Upload new에서 JAR 파일과 저장 위치를 지정합니다.
- 드라이버 옆의 추가 버튼으로 에이전트에 연결합니다.
- Restart agent를 선택해 새 드라이버를 적용합니다.
소스는 특정 드라이버 파일이 아니라 드라이버 클래스만 지정합니다. 같은 클래스의 드라이버를 에이전트에 여러 개 추가하지 않습니다.
출력 재정의
소스의 Advanced Options에서 설정한 출력 옵션은 그 소스를 사용하는 모든 JDBC 동기화에 적용됩니다. 개별 동기화에서 다시 지정하면 해당 동기화에만 적용합니다.
| 항목 | 재정의 구성 내 필수 여부 | 기본값 | 의미 |
|---|---|---|---|
Output | 필수 | Parquet | Avro 또는 Parquet입니다. |
Compression Method | 선택 | 없음 | SNAPPY, ZSTD 또는 무압축을 선택합니다. |
Fetch size | 선택 | 미지정 | 데이터베이스 왕복 호출마다 읽을 행 수입니다. |
Max file size | 선택 | 미지정 | 출력 파일의 바이트 또는 행 수 한도를 지정합니다. |
Fetch size를 늘리면 네트워크 왕복 횟수를 줄일 수 있지만 메모리를 더 사용합니다. 500에서 시작해 조정하는 것이 권장되며 드라이버가 fetch size를 지원해야 합니다.
최대 파일 크기를 바이트로 지정할 때에는 작성기 메모리 버퍼의 최소 두 배여야 합니다. Parquet 버퍼는 128MB, Avro 버퍼는 64KB입니다. 바이트 한도는 근사값이므로 실제 파일은 조금 크거나 작을 수 있습니다.
동기화와 SQL
Overview의 Explore and create syncs에서 테이블을 고른 뒤 Create sync for x datasets로 생성합니다.
선택적인 pre-query 배열은 본 질의보다 먼저 실행합니다. 데이터를 읽기 전에 데이터베이스 갱신을 시작해야 하는 경우 등에 사용할 수 있습니다.
동기화의 본 SQL 질의는 하나이며 테이블을 반환해야 합니다. 이 일반 JDBC 수집 경로에서는 저장 프로시저 호출 같은 작업을 본 질의로 수행하지 않습니다. 결과는 출력 데이터셋에 저장합니다.
개별 동기화의 Enforce precision limits는 정밀도 38을 초과하는 숫자를 거부합니다. 기본적으로 꺼져 있습니다.
증분 수집
성능이나 안정성을 개선하려면 먼저 증분 수집을 검토하고, 충분하지 않을 때 질의 병렬화를 검토합니다.
증분 수집에는 엄격하게 단조 증가하는 열이 필요합니다. Edit syncs에서 트랜잭션을 APPEND로 설정하고 Incremental을 Enable로 바꿉니다. 증분 열과 초기값을 지정하되 가져올 모든 값보다 작은 초기값을 선택합니다. 이후 실행은 이미 읽은 최대값보다 큰 행을 가져옵니다.
가상 5TB 테이블의 id를 기준으로 초기값 -1, 한도 5천만 행을 지정하면 첫 실행은 id > -1인 행을 오름차순으로 가져옵니다. 이전 최대값이 19384004822이면 다음 실행은 그보다 큰 행부터 가져옵니다.
다음은 LIMIT 구문을 지원하는 데이터베이스의 예시입니다. ?는 이전 실행의 값으로 갱신됩니다. 행 수를 제한할 때에는 증분 열의 오름차순을 유지하여 아직 읽지 않은 작은 값이 건너뛰어지지 않게 합니다.
SELECT * FROM "sales"."region"
WHERE sale_id > ?
ORDER BY sale_id ASC
LIMIT 100000
시간대가 없는 timestamp 열은 UTC로 간주하여 증분 질의를 실행합니다.
SQL 질의 병렬화
병렬화는 독립된 여러 질의를 원천에 보냅니다. 실시간으로 갱신되는 테이블은 각 질의의 실행 시점이 조금씩 달라 결과가 서로 다른 시점의 상태를 반영할 수 있습니다.
SELECT
/* FORCED_PARALLELISM_COLUMN(<column>), FORCED_PARALLELISM_SIZE(<size>) */
*
FROM <table_name>
FORCED_PARALLELISM_COLUMN에는 가능한 한 분포가 고른 숫자 열 또는 숫자를 반환하는 열 표현식을 넣습니다. FORCED_PARALLELISM_SIZE(4)는 값 범위를 나눈 네 질의와 NULL 값을 읽는 한 질의를 합쳐 다섯 질의를 동시에 실행합니다.
SELECT
/* FORCED_PARALLELISM_COLUMN(sales_id), FORCED_PARALLELISM_SIZE(4) */
*
FROM "sales"."region"
WHERE에 OR 조건이 있으면 조건 집합을 괄호로 묶습니다.
SELECT /* FORCED_PARALLELISM_COLUMN(sales_id), FORCED_PARALLELISM_SIZE(4) */
* FROM "sales"."region"
WHERE (condition1 = TRUE OR condition2 = TRUE)
Iceberg 동기화와 테이블 내보내기
사용자 정의 JDBC 소스에서 Foundry Iceberg 테이블로 직접 동기화할 수 있습니다. Foundry 워커에서 비증분 및 증분 배치 수집과 여러 쓰기 모드를 지원합니다.
스키마가 있는 Foundry 데이터셋은 JDBC 테이블로 내보낼 수 있습니다. 목적지 데이터베이스, 스키마와 테이블은 원천에 존재하는 값과 일치해야 합니다. 직접 입력하거나 Explore & autofill로 대상 테이블을 고릅니다. 내보내기 모드도 선택해야 합니다.
현재 테이블 내보내기의 배치 처리는 기본적으로 꺼져 있습니다. 활성화하면 2~5,000개 레코드를 배치 크기로 지정할 수 있으며, 드라이버가 지원하면 다음 내보내기부터 적용됩니다.
소스 상태 검사
기본적으로 60분마다 소스의 연결 가능 상태를 검사합니다. 소스에 지정한 각 에이전트에서 실행하며 JDBC 검사는 SELECT 1 질의입니다.
기존 JDBC Export task
Export tasks는 Legacy 기능이며 신규 구현에는 현재 테이블 내보내기를 사용합니다. 기존 작업은 PostgreSQL, Microsoft SQL Server, MySQL, IBM DB2, Oracle, Teradata, Snowflake와 Vertica를 지원합니다.
다음 식별자는 가상 예시입니다. Overwrite 모드는 외부 테이블 데이터를 교체합니다.
type: export-jdbc-task
exporterType: parquet
datasets:
- inputAlias: myInput # only required if you have more than 1 input
writeDirectly: true
writeMode: Overwrite
table:
database: mydb # Optional
schema: public # Optional
table: mytable
전체 설정
parallelize는 입력 데이터셋의 내보내기를 최대 8개까지 병렬 실행합니다. preSql은 내보내기 전, stagingSql은 테이블 이름 변경 전, afterSql은 내보내기 후에 실행합니다. manualTransactionManagement=true는 트랜잭션 관리를 구성자가 맡는 설정입니다.
type: export-jdbc-task
exporterType: parquet
# Parallel execution
parallelize: false # Run exports for each dataset in parallel (up to 8)
# SQL execution hooks
preSql: # SQL statements run before export
- TRUNCATE TABLE staging_table
stagingSql: # SQL statements run before table rename
- SELECT 1
afterSql: # SQL statements run after export
- INSERT INTO production_table SELECT * FROM staging_table
# Transaction management
manualTransactionManagement: false # Set true to manage transactions yourself
transactionIsolation: READ_COMMITTED # java.sql.Connection.TransactionIsolationLevel
# Dataset-specific configurations
datasets:
- inputAlias: myInput
table:
database: mydb
schema: public
table: mytable
# Write configuration
writeDirectly: false # false = use staging table first
copyMode: insert # insert or directCopy (PostgreSQL only)
batchSize: 1000 # Rows per insert statement
writeMode: ErrorIfExists # ErrorIfExists, Append, Overwrite, AppendIfPossible
# Incremental export
incrementalType: snapshot # snapshot or incremental
# Performance
exporterThreads: 1 # Parallel file export threads
# Identifier handling
quoteIdentifiers: true # Quote column names
# Transaction isolation for this export
exportTransactionIsolation: READ_UNCOMMITTED
위 예시의 TRUNCATE와 INSERT는 외부 테이블을 변경합니다. 실제 테이블 이름과 운영 영향을 확인하여 사용합니다.
쓰기 방식
| 모드 | 동작 |
|---|---|
ErrorIfExists | 기본값이며 테이블이 이미 있으면 실패합니다. |
Append | 기존 테이블에 추가합니다. |
Overwrite | 기존 테이블 데이터를 교체합니다. |
AppendIfPossible | 첫 내보내기는 교체하고 이후에는 추가합니다. |
writeDirectly=false가 기본값입니다. 먼저 {tableName}_staged_에 내보내고, staging 테이블을 최종 이름으로 바꾼 뒤 기존 테이블을 제거합니다. true이면 최종 테이블에 직접 씁니다.
copyMode=insert는 행별 INSERT와 배치 크기를 사용합니다. PostgreSQL 전용 directCopy는 파일마다 COPY 하나를 실행합니다.
quoteIdentifiers=true가 기본값입니다. 숫자로 시작하거나 공백/하이픈이 있는 열 이름, level, values 같은 예약어를 처리하기 위한 설정입니다. Oracle이나 IBM DB2에서 이후 모든 열 참조에 따옴표를 써야 하는 동작을 원하지 않으면 false 구성을 검토합니다.
증분 내보내기
incrementalType=incremental은 데이터셋마다 지정합니다. 첫 실행은 전체 스냅샷을 내보내고 마지막 트랜잭션을 기억합니다. 이후에는 그 트랜잭션이 데이터셋에 남아 있을 때 새 트랜잭션만 내보내며, 이전 트랜잭션이 없어졌으면 전체 스냅샷으로 돌아갑니다.
임시 테이블에 증분 데이터를 적재하고 SQL hook으로 최종 테이블에 반영하는 구성을 사용할 수 있습니다. writeDirectly=true는 추가 staging 테이블 생성을 피하고, AppendIfPossible은 첫 실행 교체 후 추가를 수행합니다.
type: export-jdbc-task
preSql:
- TRUNCATE TABLE mytable_incremental
datasets:
- inputAlias: myInput
table:
schema: public
table: mytable_incremental
writeDirectly: true
writeMode: AppendIfPossible
incrementalType: incremental
afterSql:
- INSERT INTO mytable SELECT * FROM mytable_incremental
데이터베이스별 조건
Teradata에서는 MULTISET 테이블을 만들고 입력의 첫 열을 행 분산 기준으로 사용합니다. 첫 열의 카디널리티가 낮아 한쪽에 행이 몰리지 않도록 열 순서를 구성합니다. 한 트랜잭션에 여러 DDL을 실행할 수 없어 DROP, CREATE, RENAME 각각의 뒤에 커밋합니다.
Teradata의 String은 기본적으로 LONG VARCHAR로 내보냅니다. 다음처럼 열별 VARCHAR 길이를 지정할 수 있습니다.
datasets:
- table:
table: mytable
dbOptions:
type: 'teradata'
columnVarcharSize:
someColumnName: 1000
Legacy Snowflake 내보내기는 batchSize를 약 50,000으로 늘리는 구성이 권장되지만 에이전트 힙 메모리를 더 사용합니다. 이는 현재 테이블 내보내기 UI의 2~5,000 배치 설정과 다른 Legacy 작업 옵션입니다.
Oracle의 기본 최대 열 길이는 255바이트이며 다음처럼 조정합니다.
datasets:
- table:
table: mytable
dbOptions:
type: 'oracle'
columnVarcharSize:
someColumnName: 1000
Legacy 내보내기 성능과 오류
parallelize=true와 데이터셋별 exporterThreads를 사용하면 입력과 파일을 병렬로 내보낼 수 있습니다. 스레드 수는 에이전트의 사용 가능한 코어 수에서 시작해 조정하고, batchSize는 데이터베이스와 메모리 한도에 맞춥니다.
PreparedStatement batch request 같은 삽입 오류가 발생하면 다음을 확인합니다.
- 첫 열을 분산 기준으로 사용하는 Teradata에서는 카디널리티가 높은 열을 앞에 둡니다.
- 대상이 요구하는 문자 인코딩을 맞춥니다. 이 Legacy Teradata 내보내기 경로에는 UTF-8 대신 ASCII 또는 Latin-1 호환 처리가 필요할 수 있습니다.
- batchSize를 1로 줄이면 느려지지만 데이터 품질이나 제약 위반을 일으킨 행을 식별할 수 있습니다.