bigquery 테이블 함수

bigquery 테이블 함수 (bigquery)

Google BigQuery의 테이블(퍼블릭 데이터셋 포함)에 SELECTINSERT 쿼리를 수행할 수 있게 해줘요. 테이블 구조는 BigQuery 테이블 스키마에서 자동으로 유추됩니다.

읽기는 BigQuery REST API(tabledata.list)를 사용하므로 기본(native) 테이블만 읽을 수 있어요(뷰, 머티리얼라이즈드 뷰, 외부 테이블은 불가). 쓰기는 스트리밍 삽입(tabledata.insertAll)을 사용하며, 프로젝트에 결제(billing)가 활성화되어 있어야 합니다.

출처: 문서

본문

Google BigQuery의 테이블(퍼블릭 데이터셋 포함)에 SELECTINSERT 쿼리를 수행할 수 있게 해줍니다. 테이블 구조는 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는 익명 접근을 허용하지 않으므로 퍼블릭 데이터셋에도 자격 증명이 필요합니다.

  1. 액세스 토큰. 유효한 OAuth 2.0 액세스 토큰(예: gcloud auth print-access-token). 토큰은 빨리 만료되므로(보통 한 시간 후), 대화형 사용에 가장 적합합니다.
  2. 서비스 계정 키(서버에 권장). Google Cloud IAM에서 만든 키 파일의 내용을 service_account_key 인자로 전달합니다. ClickHouse가 키로 JWT를 서명해 액세스 토큰과 교환하며 자동으로 갱신합니다.
  3. 갱신 토큰. 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')로 매핑됩니다.
  • NULLABLE RECORDNullable(Tuple(...))로 매핑되어, 레코드 전체 NULL이 기본 값의 Tuple로 축소되는 대신 NULL로 보존됩니다. NULL(또는 빈) 배열은 ClickHouse에서 ArrayNullable 내부에 있을 수 없으므로 빈 배열이 됩니다. BigQuery 배열은 NULL 요소를 담을 수 없으므로(ARRAY<T>ARRAY<T NOT NULL>과 동등), REPEATED 필드의 요소 타입은 Nullable이 아닙니다(Array(T), RECORD 요소는 Array(Tuple(...))). tabledata.list 응답의 NULL 요소는 잘못된 입력으로 거부됩니다.
  • 영구 BigQuery 엔진 테이블의 컬럼을 명시적으로 선언할 때, RECORD 필드는 유추된 Nullable(Tuple(...)) 대신 일반 Tuple(...)으로 선언할 수 있습니다(레코드 전체 NULL을 기본 튜플로 강제 변환하는 대가). 유추된 타입과의 허용되는 차이는 RECORDTuple을 감싸는 Nullable을 없애는 것뿐이며, 그 정확히 같은 레코드에서만 가능합니다 — 널 가능성을 다른(내부·외부) 레코드로 옮길 수는 없습니다.
  • GEOGRAPHYGeometry로 매핑됩니다. BigQuery는 GEOGRAPHY 값을 WKT 텍스트로 전송하며, 읽을 때는 Geometry의 일치하는 변형(Point, MultiPoint, Ring, LineString, MultiLineString, Polygon, MultiPolygonVariant)으로 파싱되고, 쓸 때는 WKT로 다시 직렬화됩니다. GEOMETRYCOLLECTION과 빈 지오메트리(예: POINT EMPTY)는 Geometry 대응이 없으므로, 그런 값을 담은 행을 읽으면 오류가 발생합니다. Variant는 자체로 NULL을 담으므로 NULLABLE GEOGRAPHY 필드는 Nullable(Geometry)이 아닌 Geometry로 매핑되며, NULL도 여전히 왕복됩니다.
  • JSON은 ClickHouse JSON 데이터 타입이 아닌 String으로 매핑됩니다. ClickHouse JSON 타입은 최상위에 객체({...})만 허용하는 반면, BigQuery JSON 값은 스칼라·배열·null 등 어떤 JSON 값이든 될 수 있어 그런 값을 담은 테이블을 읽지 못하기 때문입니다. 또한 JSONNullable로 감쌀 수 없어 NULLABLE 컬럼의 SQL NULL이 보존되지 않습니다. String 매핑은 무손실입니다. 최상위 객체는 CAST(value AS JSON)로 변환할 수 있습니다.
  • 정수 부분에 38자리보다 많은 BIGNUMERIC 값은 Decimal(76, 38)에 맞지 않아 오류가 발생합니다.
  • DateTime64/Date32 범위(1900~2299년)를 벗어나는 TIMESTAMP·DATE 값은 지원되지 않습니다.
  • RANGE 컬럼은 읽기 전용입니다. tabledata.insertAllRANGE<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 타입으로 표현할 수 없으므로, 그런 값을 담은 행을 읽으면 오류가 발생합니다. REQUIRED GEOGRAPHY 필드에 NULL Geometry를 쓰거나 REPEATED GEOGRAPHY 필드의 요소로 쓰는 것은 거부됩니다. BigQuery가 거기서 NULL을 받지 않기 때문입니다.
  • 술어(predicate)는 푸시다운되지 않습니다. tabledata.list는 테이블의 행만 나열하며 필터링 파라미터가 전혀 없습니다(페이지네이션·컬럼 선택·포맷 옵션만 받고, 필터링하려면 BigQuery 쿼리 잡을 실행해야 하는데 이 함수는 그렇게 하지 않음). 따라서 WHERE 조건은 행이 다운로드된 후 ClickHouse에서 적용됩니다. 전송 데이터를 줄이려면 컬럼 선택을 사용하세요.
  • 반면 LIMIT는 읽는 데이터 양을 줄입니다. 페이지는 지연(lazy) 요청되며, maxResultsmax_block_size로 설정되고, 쿼리에 충분한 행이 생기면 더 이상 페이지를 요청하지 않습니다. 단순 LIMIT n(WHERE, GROUP BY, ORDER BY 없고 nmax_block_size 미만)에서는 ClickHouse가 max_block_sizen으로 낮춰 정확히 n 행에 대해 정확히 한 번 요청하며, 그 외에는 읽기가 제한을 지난 첫 페이지 경계에서 멈춤니다(한 페이지 미만으로 초과).
  • 읽기는 명시적 컬럼 목록을 tabledata.list에 전달해 쿼리 분석 시점에 본 스키마에 고정됩니다. 컬럼 목록이 요청 URL 길이 제한을 초과하는 매우 넓은 읽기(예: 수천 개 컬럼이 있는 테이블의 SELECT *)는 고정 없이 읽는 대신 쿼리가 거부됩니다(고정되지 않은 읽기는 동시 스키마 변경으로 어긋날 수 있음). 목록이 들어맞도록 컬럼을 줄이세요. 같은 URL 길이 제한이 모든 페이지네이션 요청 전에 확인되므로(각 페이지는 불투명한 pageToken을 담음), 이후 페이지가 맞지 않는 읽기는 중간에 실패하는 대신 같은 오류로 거부됩니다.
  • 스키마를 읽은 후 BigQuery 테이블이 변경되면, 조용히 일치하지 않는 데이터를 반환·쓰는 대신 쿼리가 거부됩니다. 읽기 직전과 INSERT가 첫 행을 스트리밍하기 직전에 라이브 스키마를 다시 가져와 분석된 것과 비교합니다. (그 검사와 그 뒤에 따라오는 요청 사이의 스키마 변경 창은 닫을 수 없습니다. 스키마와 데이터가 별도 REST 요청으로 가져와지기 때문입니다.)
  • 비교는 쿼리가 분석된 스키마 스냅샷과의 비교입니다. 이 스냅샷은 테이블 함수가 구조를 해석할 때, 또는 영구 테이블(BigQuery 엔진 테이블 또는 CREATE TABLE ... AS bigquery(...)로 만든, 같은 방식으로 컬럼을 유지하는 테이블)의 경우 CREATE, ATTACH, 서버 재시작 후 첫 읽기·쓰기 시점에 캡처됩니다. 테이블 메타데이터는 BigQuery 스키마가 아닌 매핑된 ClickHouse 컬럼을 유지하므로, 테이블이 분리(또는 서버 다운)된 동안 이뤄진 스키마 변경은 거부되는 대신 다음 쿼리가 채택합니다. 선언된 컬럼은 여전히 라이브 스키마로 검증되고 행도 그 스키마로 디코딩되므로, 매핑된 ClickHouse 타입을 유지하는 변경(예: STRINGBYTES)은 같은 컬럼 타입 아래 새 타입의 규칙으로 읽힙니다.
  • 스트리밍 삽입으로 쓴 행은 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 = 1max_insert_threads = 1 설정) 중복 제거됩니다.

더 알아보기 (Learn more)