bigquery 테이블 함수
bigquery 테이블 함수 (bigquery)
Google BigQuery의 테이블(퍼블릭 데이터셋 포함)에 SELECT와 INSERT 쿼리를 수행할 수 있게 해줘요. 테이블 구조는 BigQuery 테이블 스키마에서 자동으로 유추됩니다.
읽기는 BigQuery REST API(tabledata.list)를 사용하므로 기본(native) 테이블만 읽을 수 있어요(뷰, 머티리얼라이즈드 뷰, 외부 테이블은 불가). 쓰기는 스트리밍 삽입(tabledata.insertAll)을 사용하며, 프로젝트에 결제(billing)가 활성화되어 있어야 합니다.
출처: 문서
본문
Google BigQuery의 테이블(퍼블릭 데이터셋 포함)에 SELECT와 INSERT 쿼리를 수행할 수 있게 해줍니다. 테이블 구조는 BigQuery 테이블 스키마에서 자동으로 유추됩니다.
읽기는 BigQuery REST API(tabledata.list)를 사용하므로 기본 테이블만 읽을 수 있습니다(뷰, 머티리얼라이즈드 뷰, 외부 테이블은 불가). 쓰기는 스트리밍 삽입(tabledata.insertAll)을 사용하며, 프로젝트에 결제가 활성화되어 있어야 합니다.
구문
bigquery(project, dataset, table[, access_token][, key = value, ...])
bigquery(named_collection[, key = value, ...])
인자
| 인자 | 설명 |
|---|---|
project |
데이터셋을 소유한 Google Cloud 프로젝트. 퍼블릭 데이터셋의 경우 데이터셋의 프로젝트(예: bigquery-public-data). |
dataset |
데이터셋 이름. |
table |
테이블 이름. |
access_token |
OAuth 2.0 액세스 토큰(선택적 위치 인자, 인증 참고). |
project, dataset, table, access_token 인자는 key = value 형식으로도 줄 수 있습니다. 위치 인자는 이 순서로 슬롯을 채우며, 인자를 위치와 키로 동시에(또는 같은 키를 두 번) 지정하면 오류입니다.
다음 인자들은 key = value 형식(또는 named collection의 키)으로 지정할 수 있습니다:
| 키 | 설명 |
|---|---|
access_token |
OAuth 2.0 액세스 토큰. |
service_account_key |
JSON 형식의 Google 서비스 계정 키 파일 내용. |
client_id |
OAuth 2.0 클라이언트 ID(client_secret·refresh_token과 함께 사용). |
client_secret |
OAuth 2.0 클라이언트 시크릿. |
refresh_token |
OAuth 2.0 갱신 토큰. |
billing_project |
할당량과 결제를 귀속시킬 선택적 프로젝트(X-Goog-User-Project 헤더로 전송). |
base_url |
API 엔드포인트. 기본값 https://bigquery.googleapis.com. 테스트·에뮬레이터용으로 변경 가능. |
token_url |
테스트·에뮬레이터용 OAuth 토큰 엔드포인트 오버라이드. 기본적으로 서비스 계정 키의 token_uri 또는 https://oauth2.googleapis.com/token. |
인증
정확히 하나의 인증 방법을 제공해야 합니다. BigQuery는 익명 접근을 허용하지 않으므로 퍼블릭 데이터셋에도 자격 증명이 필요합니다.
- 액세스 토큰. 유효한 OAuth 2.0 액세스 토큰(예:
gcloud auth print-access-token). 토큰은 빨리 만료되므로(보통 한 시간 후), 대화형 사용에 가장 적합합니다. - 서비스 계정 키(서버에 권장). Google Cloud IAM에서 만든 키 파일의 내용을
service_account_key인자로 전달합니다. ClickHouse가 키로 JWT를 서명해 액세스 토큰과 교환하며 자동으로 갱신합니다. - 갱신 토큰.
gcloud auth application-default login후~/.config/gcloud/application_default_credentials.json에서 가져온client_id,client_secret,refresh_token을 전달합니다.
매 쿼리마다 지정하지 않도록 자격 증명을 named collection에 저장하세요. named collection에서 만든 영구 테이블(BigQuery 테이블 엔진 또는 CREATE TABLE ... AS bigquery(...))은 컬렉션의 의존성으로 등록되므로, 테이블이 존재하는 동안 DROP NAMED COLLECTION이 차단됩니다.
데이터 타입 매핑
| BigQuery 타입 | ClickHouse 타입 |
|---|---|
STRING |
String |
BYTES |
String (원시 바이트) |
INTEGER / INT64 |
Int64 |
FLOAT / FLOAT64 |
Float64 |
BOOLEAN / BOOL |
Bool |
TIMESTAMP |
DateTime64(6, 'UTC') |
DATE |
Date32 |
TIME |
Time64(6) |
DATETIME |
DateTime64(6, 'UTC') |
NUMERIC / DECIMAL |
Decimal(38, 9), 또는 파라미터화 시 Decimal(P, S) |
BIGNUMERIC |
Decimal(76, 38), 또는 파라미터화 시 Decimal(P, S) |
GEOGRAPHY |
Geometry (WKT에서 파싱) |
JSON |
String |
INTERVAL |
String |
RANGE |
String (읽기 전용) |
RECORD / STRUCT |
Tuple, 또는 NULLABLE 모드에서 Nullable(Tuple) |
REPEATED 모드 |
요소 타입의 Array(비-Nullable 요소, RECORD 요소는 Array(Tuple(...)) 포함). BigQuery 배열은 NULL 요소를 담을 수 없기 때문 |
NULLABLE 모드 |
Nullable (GEOGRAPHY 제외 — Geometry 타입이 자체로 NULL을 담음) |
참고:
- BigQuery
DATETIME은 타임존이 없습니다. 표시 값이 서버 타임존에 의존하지 않도록DateTime64(6, 'UTC')로 매핑됩니다. NULLABLERECORD는Nullable(Tuple(...))로 매핑되어, 레코드 전체NULL이 기본 값의Tuple로 축소되는 대신NULL로 보존됩니다.NULL(또는 빈) 배열은 ClickHouse에서Array가Nullable내부에 있을 수 없으므로 빈 배열이 됩니다. BigQuery 배열은NULL요소를 담을 수 없으므로(ARRAY<T>는ARRAY<T NOT NULL>과 동등),REPEATED필드의 요소 타입은Nullable이 아닙니다(Array(T),RECORD요소는Array(Tuple(...))).tabledata.list응답의NULL요소는 잘못된 입력으로 거부됩니다.- 영구
BigQuery엔진 테이블의 컬럼을 명시적으로 선언할 때,RECORD필드는 유추된Nullable(Tuple(...))대신 일반Tuple(...)으로 선언할 수 있습니다(레코드 전체NULL을 기본 튜플로 강제 변환하는 대가). 유추된 타입과의 허용되는 차이는RECORD의Tuple을 감싸는Nullable을 없애는 것뿐이며, 그 정확히 같은 레코드에서만 가능합니다 — 널 가능성을 다른(내부·외부) 레코드로 옮길 수는 없습니다. GEOGRAPHY는 Geometry로 매핑됩니다. BigQuery는GEOGRAPHY값을 WKT 텍스트로 전송하며, 읽을 때는Geometry의 일치하는 변형(Point,MultiPoint,Ring,LineString,MultiLineString,Polygon,MultiPolygon의Variant)으로 파싱되고, 쓸 때는 WKT로 다시 직렬화됩니다.GEOMETRYCOLLECTION과 빈 지오메트리(예:POINT EMPTY)는Geometry대응이 없으므로, 그런 값을 담은 행을 읽으면 오류가 발생합니다.Variant는 자체로NULL을 담으므로NULLABLEGEOGRAPHY필드는Nullable(Geometry)이 아닌Geometry로 매핑되며,NULL도 여전히 왕복됩니다.JSON은 ClickHouseJSON데이터 타입이 아닌String으로 매핑됩니다. ClickHouseJSON타입은 최상위에 객체({...})만 허용하는 반면, BigQueryJSON값은 스칼라·배열·null등 어떤 JSON 값이든 될 수 있어 그런 값을 담은 테이블을 읽지 못하기 때문입니다. 또한JSON은Nullable로 감쌀 수 없어NULLABLE컬럼의 SQLNULL이 보존되지 않습니다.String매핑은 무손실입니다. 최상위 객체는CAST(value AS JSON)로 변환할 수 있습니다.- 정수 부분에 38자리보다 많은
BIGNUMERIC값은Decimal(76, 38)에 맞지 않아 오류가 발생합니다. DateTime64/Date32범위(1900~2299년)를 벗어나는TIMESTAMP·DATE값은 지원되지 않습니다.RANGE컬럼은 읽기 전용입니다.tabledata.insertAll은RANGE<T>값을 구조화된{start, end}객체로 기대하는데, 이를String매핑에서 재구성할 수 없으므로RANGE컬럼에 삽입하면 오류가 발생합니다.INT64값은 API가 JSON 숫자를 double로 파싱하므로(그러지 않으면[-2^53 + 1, 2^53 - 1]밖의 값을 손상시킴) 십진 문자열로tabledata.insertAll에 전송됩니다.
예제
gcloud 토큰으로 퍼블릭 데이터셋 읽기:
SELECT word, sum(word_count) AS c
FROM bigquery('bigquery-public-data', 'samples', 'shakespeare', '<access token>')
GROUP BY word
ORDER BY c DESC
LIMIT 5;
서비스 계정 키 파일로 프라이빗 테이블 읽기:
SELECT count()
FROM bigquery('my-project', 'my_dataset', 'my_table',
service_account_key = '{"type": "service_account", "private_key": "...", "client_email": "...", ...}');
데이터 삽입(스트리밍 삽입, 결제 활성화 필요):
INSERT INTO FUNCTION bigquery('my-project', 'my_dataset', 'my_table', '<access token>')
SELECT number AS id, toString(number) AS name FROM numbers(10);
named collection 사용:
<clickhouse>
<named_collections>
<my_bigquery>
<project>my-project</project>
<dataset>my_dataset</dataset>
<service_account_key><![CDATA[{"type": "service_account", ...}]]></service_account_key>
</my_bigquery>
</named_collections>
</clickhouse>
SELECT * FROM bigquery(my_bigquery, table = 'my_table');
제한 사항
- 기본 BigQuery 테이블만 읽을 수 있습니다. 뷰와 외부 테이블은 BigQuery 쿼리 잡을 실행해야 하는데, 이 함수는 그렇게 하지 않습니다.
RANGE컬럼은 읽을 수 있지만(String으로) 쓸 수는 없습니다.RANGE컬럼에 삽입하면 오류입니다.GEOMETRYCOLLECTION또는 빈 지오메트리인GEOGRAPHY값은Geometry타입으로 표현할 수 없으므로, 그런 값을 담은 행을 읽으면 오류가 발생합니다.REQUIREDGEOGRAPHY필드에NULLGeometry를 쓰거나REPEATEDGEOGRAPHY필드의 요소로 쓰는 것은 거부됩니다. BigQuery가 거기서NULL을 받지 않기 때문입니다.- 술어(predicate)는 푸시다운되지 않습니다.
tabledata.list는 테이블의 행만 나열하며 필터링 파라미터가 전혀 없습니다(페이지네이션·컬럼 선택·포맷 옵션만 받고, 필터링하려면 BigQuery 쿼리 잡을 실행해야 하는데 이 함수는 그렇게 하지 않음). 따라서WHERE조건은 행이 다운로드된 후 ClickHouse에서 적용됩니다. 전송 데이터를 줄이려면 컬럼 선택을 사용하세요. - 반면
LIMIT는 읽는 데이터 양을 줄입니다. 페이지는 지연(lazy) 요청되며,maxResults는max_block_size로 설정되고, 쿼리에 충분한 행이 생기면 더 이상 페이지를 요청하지 않습니다. 단순LIMIT n(WHERE,GROUP BY,ORDER BY없고n이max_block_size미만)에서는 ClickHouse가max_block_size를n으로 낮춰 정확히n행에 대해 정확히 한 번 요청하며, 그 외에는 읽기가 제한을 지난 첫 페이지 경계에서 멈춤니다(한 페이지 미만으로 초과). - 읽기는 명시적 컬럼 목록을
tabledata.list에 전달해 쿼리 분석 시점에 본 스키마에 고정됩니다. 컬럼 목록이 요청 URL 길이 제한을 초과하는 매우 넓은 읽기(예: 수천 개 컬럼이 있는 테이블의SELECT *)는 고정 없이 읽는 대신 쿼리가 거부됩니다(고정되지 않은 읽기는 동시 스키마 변경으로 어긋날 수 있음). 목록이 들어맞도록 컬럼을 줄이세요. 같은 URL 길이 제한이 모든 페이지네이션 요청 전에 확인되므로(각 페이지는 불투명한pageToken을 담음), 이후 페이지가 맞지 않는 읽기는 중간에 실패하는 대신 같은 오류로 거부됩니다. - 스키마를 읽은 후 BigQuery 테이블이 변경되면, 조용히 일치하지 않는 데이터를 반환·쓰는 대신 쿼리가 거부됩니다. 읽기 직전과
INSERT가 첫 행을 스트리밍하기 직전에 라이브 스키마를 다시 가져와 분석된 것과 비교합니다. (그 검사와 그 뒤에 따라오는 요청 사이의 스키마 변경 창은 닫을 수 없습니다. 스키마와 데이터가 별도 REST 요청으로 가져와지기 때문입니다.) - 비교는 쿼리가 분석된 스키마 스냅샷과의 비교입니다. 이 스냅샷은 테이블 함수가 구조를 해석할 때, 또는 영구 테이블(
BigQuery엔진 테이블 또는CREATE TABLE ... AS bigquery(...)로 만든, 같은 방식으로 컬럼을 유지하는 테이블)의 경우CREATE,ATTACH, 서버 재시작 후 첫 읽기·쓰기 시점에 캡처됩니다. 테이블 메타데이터는 BigQuery 스키마가 아닌 매핑된 ClickHouse 컬럼을 유지하므로, 테이블이 분리(또는 서버 다운)된 동안 이뤄진 스키마 변경은 거부되는 대신 다음 쿼리가 채택합니다. 선언된 컬럼은 여전히 라이브 스키마로 검증되고 행도 그 스키마로 디코딩되므로, 매핑된 ClickHouse 타입을 유지하는 변경(예:STRING→BYTES)은 같은 컬럼 타입 아래 새 타입의 규칙으로 읽힙니다. - 스트리밍 삽입으로 쓴 행은 BigQuery 스트리밍 버퍼에 들어가며, 이후 읽기에 보이기까지 시간이 걸릴 수 있습니다.
- 큰
INSERT는 배치로tabledata.insertAll에 전송됩니다. 요청당 최대 500행이며, 각 요청이 BigQuery의 10MB 요청 크기 제한을 넘지 않도록 분할됩니다(해당 제한보다 큰 단일 행은 명확한 오류로 거부). - 쓰기는 원자적이지 않으며, 단일
tabledata.insertAll요청도 부분 성공할 수 있습니다. BigQuery는 한 요청의 일부 행을 커밋하면서 나머지는insertErrors로 거부할 수 있습니다. 요청도 서로 독립적으로 커밋되므로, 앞선 배치가 수락된 후 이후 배치가 거부될 수 있습니다. 두 경우 모두 쿼리는 오류를 보고하지만 이미 커밋된 행은 BigQuery에 남습니다. 중복을 줄이기 위해 각 행은 쿼리 ID와 스트림 내 행의 서수 위치에서 파생된 안정적인insertId와 함께 전송되며, BigQuery는 스트리밍 삽입 창 내에서 best-effort 중복 제거에 이를 사용합니다. BigQuery의 128자insertId제한보다 긴query_id는 고정 길이 접두사로 해시되며, 그query_id에 대해 안정적으로 유지됩니다.insertId가 서수 위치에 의존하므로, 재실행이 행을 같은 순서로 만들 때만 중복 제거가 신뢰할 수 있습니다. 전송 수준 재시도는 항상 안전하며, 같은query_id로 같은INSERT를 재실행하는 것은 행을 같은 순서로 제시할 때만(예: 단일 스레드 삽입, 또는 결정적 정렬 — 시도 사이에 청크 순서가 바뀔 수 있는 병렬INSERT ... SELECT에는max_threads = 1과max_insert_threads = 1설정) 중복 제거됩니다.