Loading...
Loading...
Compare original and translation side by side
bq loadbq loadgcloudgcloudgcloudbqgcloud config set project PROJECT_ID
gcloud config set compute/region REGIONgcloud config set compute/regionbqcompute/regionUS--locationbq~/.bigqueryrcdefault_locationUSEUus-central1europe-west4--locationbqbigquery.googleapis.comstorage.googleapis.comgcloud services enable bigquery.googleapis.com storage.googleapis.comgcloud auth logingcloud auth application-default loginGOOGLE_APPLICATION_CREDENTIALSroles/bigquery.jobUserroles/bigquery.dataEditorbq mkroles/storage.objectViewerpip install pyyaml==6.0.2bqUSEUUSEUus-central1gcloud storage rm -r gs://BUCKET/EXPORT_PREFIXbq rm -r -f PROJECT_ID:DATASET_IDgcloudbqgcloud config set project PROJECT_ID
gcloud config set compute/region REGIONgcloud config set compute/regionbqcompute/regionbq--location~/.bigqueryrcdefault_locationUSUSEUus-central1europe-west4bq--locationbigquery.googleapis.comstorage.googleapis.comgcloud services enable bigquery.googleapis.com storage.googleapis.comgcloud auth logingcloud auth application-default loginGOOGLE_APPLICATION_CREDENTIALSroles/bigquery.jobUserroles/bigquery.dataEditorbq mkroles/storage.objectViewerpip install pyyaml==6.0.2bqUSEUUSEUus-central1gcloud storage rm -r gs://BUCKET/EXPORT_PREFIXbq rm -r -f PROJECT_ID:DATASET_IDflowchart TD
subgraph 1. Inputs
A1["Translation Output Directory / Cloud Storage URI<br>gs://bucket/translation_output/metadata/"]
A2["Staged Parquet Files<br>gs://bucket/data_unload/TABLE/*.parquet"]
end
subgraph 2. Ingestion Pipeline
B1["1. Ensure Dataset Exists<br>bq mk --dataset --location=LOCATION DATASET"]
B2["2. Concurrent Parquet Ingestion<br>bq load --source_format=PARQUET --replace=true<br>Auto-creates native tables"]
B3["3. Row Count Audit<br>Print BigQuery Row Counts for Comparison"]
B4["4. Deploy Consumption Views<br>Deploys views directly from consolidated views.sql or relations/"]
end
A1 & A2 --> B1 --> B2 --> B3 --> B4flowchart TD
subgraph 1. 输入
A1["翻译输出目录 / Cloud Storage URI<br>gs://bucket/translation_output/metadata/"]
A2["暂存的 Parquet 文件<br>gs://bucket/data_unload/TABLE/*.parquet"]
end
subgraph 2. 导入流水线
B1["1. 确保数据集存在<br>bq mk --dataset --location=LOCATION DATASET"]
B2["2. 并发 Parquet 导入<br>bq load --source_format=PARQUET --replace=true<br>自动创建原生表"]
B3["3. 行数审计<br>输出 BigQuery 行数供比较"]
B4["4. 部署消费视图<br>直接从合并后的 views.sql 或 relations/ 部署视图"]
end
A1 & A2 --> B1 --> B2 --> B3 --> B4[!TIP] Migration workflow context: Before running the loader, translate source schemas and views into GoogleSQL by using theskill and stage exported source table Parquet files in Cloud Storage. After loading tables and deploying views, compare row counts and data aggregates against the source database.bigquery-migration-sql-translator
--translation-metadata-dirbq loadTIMESTAMPDATETIMESTRING(n)NUMERIC(p, s)metadata/config/DATABASE/SCHEMA/*.yamlsourceNameexternalTableNameexternalTableDdlPathrelations/db_DATABASE/schema_SCHEMA/VIEW.sqlviews.sqlCREATE VIEWCREATE OR REPLACE VIEW--parquet-base-uriBASE_URIBASE_URI/SCHEMA/TABLE/*.parquetBASE_URI/TABLE/*.parquetgcloud storage cp -r LOCAL_DIR/SCHEMA gs://BUCKET/data_unload/data_unload/SCHEMA/--dataset[!TIP] 迁移工作流上下文:在运行加载器之前,使用skill 将源 schema 和视图转换为 GoogleSQL,并在 Cloud Storage 中暂存导出的源表 Parquet 文件。加载表并部署视图后,将行数和数据聚合结果与源数据库进行比较。bigquery-migration-sql-translator
--translation-metadata-dirbq loadTIMESTAMPDATETIMESTRING(n)NUMERIC(p, s)metadata/config/DATABASE/SCHEMA/*.yamlsourceNameexternalTableNameexternalTableDdlPathrelations/db_DATABASE/schema_SCHEMA/VIEW.sqlviews.sqlCREATE VIEWCREATE OR REPLACE VIEW--parquet-base-uriBASE_URIBASE_URI/SCHEMA/TABLE/*.parquetBASE_URI/TABLE/*.parquetgcloud storage cp -r LOCAL_DIR/SCHEMA gs://BUCKET/data_unload/data_unload/SCHEMA/--datasetbq loadbq loadPROJECT_ID="PROJECT_ID"
DATASET_ID="DATASET_ID"
LOCATION="LOCATION"
TABLE_NAME="TABLE_NAME"
BUCKET="BUCKET"
PREFIX="data_unload"
bq show --dataset --project_id=${PROJECT_ID} ${DATASET_ID} >/dev/null 2>&1 || \
bq mk --dataset --project_id=${PROJECT_ID} --location=${LOCATION} ${DATASET_ID}PROJECT_IDDATASET_IDLOCATIONus-central1TABLE_NAMEBUCKETPROJECT_ID="PROJECT_ID"
DATASET_ID="DATASET_ID"
LOCATION="LOCATION"
TABLE_NAME="TABLE_NAME"
BUCKET="BUCKET"
PREFIX="data_unload"
bq show --dataset --project_id=${PROJECT_ID} ${DATASET_ID} >/dev/null 2>&1 || \
bq mk --dataset --project_id=${PROJECT_ID} --location=${LOCATION} ${DATASET_ID}PROJECT_IDDATASET_IDLOCATIONus-central1TABLE_NAMEBUCKET--decimal_target_types=NUMERIC --decimal_target_types=BIGNUMERIC --decimal_target_types=STRINGNUMERICBIGNUMERICSTRINGDECIMAL(p, s)p - s <= 29, s <= 9NUMERICp - s <= 38, s <= 38DECIMAL(38, 10)BIGNUMERICDECIMAL256STRINGbq load \
--project_id=${PROJECT_ID} \
--location=${LOCATION} \
--source_format=PARQUET \
--replace=true \
--decimal_target_types=NUMERIC \
--decimal_target_types=BIGNUMERIC \
--decimal_target_types=STRING \
${DATASET_ID}.${TABLE_NAME} \
"gs://${BUCKET}/${PREFIX}/${TABLE_NAME}/*.parquet"--replace=trueJSONINTERVALRANGETRUNCATE TABLE--replace=false--replace=true--schemaJSON_WRAP_JSON_QUERY_WITH_PARSE_JSON = FalseJSON_QUERY()SAFE.PARSE_JSON()JSONSTRINGJSONTIMESTAMPTIMESTAMPisAdjustedToUTC=falseTIMESTAMP WITHOUT TIME ZONEDATETIMEDATETIMEDATETIME(column)CREATE OR REPLACE TABLE `PROJECT_ID.DATASET_ID.TABLE_NAME` AS
SELECT * REPLACE (DATETIME(created_at) AS created_at)
FROM `PROJECT_ID.DATASET_ID.TABLE_NAME`;--decimal_target_types=NUMERIC --decimal_target_types=BIGNUMERIC --decimal_target_types=STRINGDECIMAL(p, s)NUMERICBIGNUMERICSTRINGp - s <= 29, s <= 9NUMERICp - s <= 38, s <= 38DECIMAL(38, 10)BIGNUMERICDECIMAL256STRINGbq load \
--project_id=${PROJECT_ID} \
--location=${LOCATION} \
--source_format=PARQUET \
--replace=true \
--decimal_target_types=NUMERIC \
--decimal_target_types=BIGNUMERIC \
--decimal_target_types=STRING \
${DATASET_ID}.${TABLE_NAME} \
"gs://${BUCKET}/${PREFIX}/${TABLE_NAME}/*.parquet"--replace=trueJSONINTERVALRANGETRUNCATE TABLE--replace=false--replace=true--schemaJSON_WRAP_JSON_QUERY_WITH_PARSE_JSON = FalseSTRINGJSONJSON_QUERY()SAFE.PARSE_JSON()JSONTIMESTAMPTIMESTAMPisAdjustedToUTC=falseTIMESTAMP WITHOUT TIME ZONEDATETIMEDATETIMEDATETIME(column)CREATE OR REPLACE TABLE `PROJECT_ID.DATASET_ID.TABLE_NAME` AS
SELECT * REPLACE (DATETIME(created_at) AS created_at)
FROM `PROJECT_ID.DATASET_ID.TABLE_NAME`;bq query \
--project_id=${PROJECT_ID} \
--location=${LOCATION} \
--use_legacy_sql=false \
"SELECT '${TABLE_NAME}' AS table_name, count(*) AS row_count FROM \`${PROJECT_ID}\`.\`${DATASET_ID}\`.\`${TABLE_NAME}\`;"bq query \
--project_id=${PROJECT_ID} \
--location=${LOCATION} \
--use_legacy_sql=false \
"SELECT '${TABLE_NAME}' AS table_name, count(*) AS row_count FROM \`${PROJECT_ID}\`.\`${DATASET_ID}\`.\`${TABLE_NAME}\`;"assets/bq_loader_template.pyassets/bq_loader_template.pyassets/bq_loader_template.pyassets/bq_loader_template.pyassets/bq_loader_template.pySKILL_DIR./bq_loader.pycpSKILL_DIRSKILL.mdcp SKILL_DIR/assets/bq_loader_template.py ./bq_loader.py# CUSTOMIZE:# DEFAULT SCAFFOLDING# CUSTOMIZE: Schema Overrides & Partitioningbq load--time_partitioning_field--clustering_fieldsload_parquet_table()# CUSTOMIZE: Custom View Rewriting & Deployment_rewrite_view_sql()deploy_views()_WRAP_JSON_QUERY_WITH_PARSE_JSON = FalseJSON# CUSTOMIZE: Connection & CLI Wrapperbq--default_kms_keyensure_dataset()--destination_kms_key--reservation_idload_parquet_table()execute_sql()# CUSTOMIZE: Post-Load Auditingaudit_row_counts()# Direct from a Cloud Storage translation_output URI with concurrency:
python3 ./bq_loader.py \
--project "PROJECT_ID" \
--dataset "DATASET_ID" \
--location "LOCATION" \
--translation-metadata-dir "gs://BUCKET/translation_output/metadata/" \
--parquet-base-uri "gs://BUCKET/data_unload/" \
--concurrency 8
# Using local translation output folder:
python3 ./bq_loader.py \
--project "PROJECT_ID" \
--dataset "DATASET_ID" \
--location "LOCATION" \
--translation-metadata-dir "TRANSLATION_OUTPUT/metadata" \
--parquet-base-uri "gs://BUCKET/data_unload/" \
--concurrency 4bqNot found: Table ...All N views successfully deployed across M passes.cpSKILL_DIRassets/bq_loader_template.py./bq_loader.pySKILL_DIRSKILL.mdcp SKILL_DIR/assets/bq_loader_template.py ./bq_loader.py# CUSTOMIZE:# DEFAULT SCAFFOLDING# CUSTOMIZE: Schema Overrides & Partitioningload_parquet_table()bq load--time_partitioning_field--clustering_fields# CUSTOMIZE: Custom View Rewriting & Deployment_rewrite_view_sql()deploy_views()JSON_WRAP_JSON_QUERY_WITH_PARSE_JSONFalse# CUSTOMIZE: Connection & CLI Wrapperbqensure_dataset()--default_kms_keyload_parquet_table()execute_sql()--destination_kms_key--reservation_id# CUSTOMIZE: Post-Load Auditingaudit_row_counts()# Directly from a Cloud Storage translation_output URI with concurrency:
python3 ./bq_loader.py \
--project "PROJECT_ID" \
--dataset "DATASET_ID" \
--location "LOCATION" \
--translation-metadata-dir "gs://BUCKET/translation_output/metadata/" \
--parquet-base-uri "gs://BUCKET/data_unload/" \
--concurrency 8
# Using local translation output folder:
python3 ./bq_loader.py \
--project "PROJECT_ID" \
--dataset "DATASET_ID" \
--location "LOCATION" \
--translation-metadata-dir "TRANSLATION_OUTPUT/metadata" \
--parquet-base-uri "gs://BUCKET/data_unload/" \
--concurrency 4bqNot found: Table ...All N views successfully deployed across M passes.--project--dataset--parquet-base-urigs://BUCKET/path/--translation-metadata-dir--locationus-central1--concurrency4bq load--project--dataset--parquet-base-urigs://BUCKET/path/--translation-metadata-dir--locationus-central1--concurrency4bq load