选定了目标表格式后。本文档在此基础上完成 BigQuery schema 的翻译,即列级类型映射、复杂类型(STRUCT、ARRAY、MAP)转换、分区策略转换。
目标
把任何 BigQuery 标量类型对应到 MaxCompute 等价类型,并知道精度和时区上何时需要特别关注。
把
RECORD/STRUCT与ARRAY<STRUCT>列翻译成 MaxCompute DDL,包含嵌套场景。使用 MaxCompute 原生
UNNEST,以与 BigQuery 一致的查询形式展开ARRAY<STRUCT>列。
能力说明
标量类型映射
BigQuery 类型 | MaxCompute 类型 | 说明 |
INT64 | BIGINT | 均为 64 位有符号整数 |
FLOAT64 | DOUBLE | 均为 64 位 IEEE 754 |
NUMERIC | DECIMAL(38, 9) | BigQuery NUMERIC 固定精度 38 位 / 9 位小数 |
NUMERIC(p, s) | DECIMAL(p, s) | 指定精度时直接映射;要求 p ≤ 38 |
NUMERIC(p) | DECIMAL(p, 0) | 仅指定整数精度时小数位为 0 |
BIGNUMERIC | DECIMAL(38, 18) | 默认精度 (38, 18),可由用户配置 |
BIGNUMERIC(p, s) p ≤ 38 且 s ≤ 30 | DECIMAL(p, s) | 精度和小数位均在 MaxCompute 范围内时直接映射 |
BIGNUMERIC(p, s) p > 38 或 s > 30 | 不支持 | MMS 无法自动迁移。迁移前需在源侧审计: |
BOOLEAN | BOOLEAN | 完全兼容 |
STRING | STRING | 兼容,MaxCompute 单值上限 8 MB |
BYTES | BINARY | 兼容 |
DATE | DATE | 日粒度,兼容 |
DATETIME | TIMESTAMP_NTZ | BigQuery DATETIME 无时区,映射到 TIMESTAMP_NTZ 保留原始值 |
TIMESTAMP | TIMESTAMP_NTZ | BigQuery TIMESTAMP 内部以 UTC 存储绝对时间点。迁移到 TIMESTAMP_NTZ 后,所有值以 UTC 存储,无时区语义。查询侧如需按业务时区展示,使用 |
TIME | BIGINT | MaxCompute 无独立 TIME 类型。BigQuery TIME 以午夜零点以来的微秒数存储(范围 0 ~ 86,399,999,999),直接映射为 BIGINT。GoTerra 之后新增的 TIME_* 函数可处理微秒编码 |
GEOGRAPHY | GEOGRAPHY | MaxCompute 原生支持 GEOGRAPHY 类型 |
INTERVAL | INTERVAL | MaxCompute 支持 INTERVAL_YEAR_MONTH / INTERVAL_DAY_TIME |
RANGE | STRING | MaxCompute 无原生 RANGE 类型;以字符串表示区间边界 |
精度注意事项:
BIGNUMERIC(p, s) 中 p ≤ 38 且 s ≤ 30 时直接映射为 DECIMAL(p, s);p > 38 或 s > 30 时可通过 DECIMAL256(p, s) 映射,覆盖最高 76 位总精度;
超过 76 位的值无法迁移,迁移前检查:
SELECT COUNT(*) FROM t WHERE CAST(col AS STRING) LIKE '%.%' AND LENGTH(REGEXP_EXTRACT(CAST(col AS STRING), r'\d+')) > 76。
时区注意事项:
BigQuery TIMESTAMP 内部以 UTC 存储绝对时间点,按用户时区展示。迁到 TIMESTAMP_NTZ 后,值仍以 UTC 存储,但不再携带时区语义
SET odps.sql.timezone对 TIMESTAMP_NTZ 列无效。查询侧如需按业务时区展示,显式转换:FROM_UTC_TIMESTAMP(col, 'Asia/Shanghai')。BigQuery DATETIME 是无时区的:2026-07-14 09:00:00 不带时区。映射到 TIMESTAMP_NTZ,保留原始值,不做隐式 UTC 偏移。
复杂类型映射
BigQuery 类型 | 统一映射 | 说明 |
JSON | JSON | 均为原生类型 |
ARRAY<T> | ARRAY<T> | 元素类型按标量映射表递归转换。BigQuery 不允许 ARRAY<ARRAY<T>> 直接嵌套,MaxCompute 同理 |
STRUCT<...> | STRUCT<...> | 字段分隔符不同:BigQuery <name type>,MaxCompute <name : type>。BigQuery 嵌套上限 15 层,MaxCompute 20 层 |
ARRAY<STRUCT<...>> | ARRAY<STRUCT<...>> | BigQuery 最常用的组合。MaxCompute 已原生支持 UNNEST 展开,语法基本一致 |
ARRAY<JSON> | ARRAY<STRING> | MaxCompute 不支持复杂类型内嵌 JSON,降级为 STRING |
STRUCT 内含 JSON 字段 | 不支持 | 如 STRUCT<a: JSON> 不可迁移,需源侧预处理 |
STRUCT 与嵌套 STRUCT
两个平台都支持任意深度的 STRUCT 嵌套,但在 DDL 语法、构造方式、NULL 处理和 Schema 演进方面存在差异。
完整关于MaxCompute Struct 数据类型介绍请参考:STRUCT数据类型
DDL 语法
字段分隔符:BigQuery 使用
<name type>,MaxCompute 使用<name : type>。尾逗号:两侧的
STRUCT<...>内均不允许。
-- BigQuery
CREATE TABLE user_events (
user_id INT64,
device STRUCT<
os STRING,
version STRING,
model STRING
>
);
-- MaxCompute
CREATE TABLE user_events (
user_id BIGINT,
device STRUCT<
os : STRING,
version : STRING,
model : STRING
>
) TBLPROPERTIES ("table.format.version" = "2");DDL —— 3 层嵌套 STRUCT
-- MaxCompute
CREATE TABLE user_events (
user_id BIGINT,
device STRUCT<
os : STRING,
version : STRING,
hardware : STRUCT<
model : STRING,
cpu : STRUCT<
cores : INT,
arch : STRING
>
>
>
) TBLPROPERTIES ("table.format.version" = "2");嵌套深度上限
平台 | STRUCT 最大嵌套深度 |
BigQuery | 15 |
MaxCompute | 20 |
MaxCompute 嵌套深度上限更大,任意 BigQuery STRUCT 层级都可以直接翻译。
注意,MaxCompute 单个 STRUCT 值(含所有嵌套字段)序列化后不应超过 1 MB,否则计算时可能触发 OOM。迁移前建议在 BigQuery 侧对字段大小进行估算。
字面量构造
BigQuery 提供三种 STRUCT 构造语法,MaxCompute 提供三种对应函数。
操作 | BigQuery | MaxCompute | 说明 |
命名式 | STRUCT('ios' AS os, '17.0' AS version) |
| 语法一致。MaxCompute 称为 STRUCT EXPRESSION |
位置式 | STRUCT('ios', '17.0') |
| BigQuery 字段匿名;MaxCompute 自动命名为 col1, col2 |
键值对式 | STRUCT('ios' AS os, ...) |
| MaxCompute 的 NAMED_STRUCT 以 (name, value, name, value, ...) 形式传参 |
全表构造 | SELECT AS STRUCT * FROM t |
| 将整行打包为 STRUCT |
含 NULL 字段 | STRUCT(NULL AS a, 2 AS b) | 需 | 仅 STRUCT EXPRESSION 支持,STRUCT/NAMED_STRUCT 函数不支持 NULL |
字段访问 | t.device.os | t.device.os | 完全相同 |
Schema 演进
BigQuery:SQL DDL 不支持对已有 STRUCT 内部增删改字段;但通过 bq CLI / API 如 update、 tables.patch 可以添加嵌套字段。删除和重命名任何方式都不支持。
MaxCompute:ALTER TABLE 不支持对已有 STRUCT 内部做增删改字段(与 BQ DDL 行为一致)。
ARRAY of STRUCT 展开
ARRAY<STRUCT>(例如 cart_items 列、event_params 列)是 BigQuery 最常用的结构之一。MaxCompute 已原生支持 UNNEST,提供三种展开模式,覆盖 BigQuery 的所有常见用法。
完整关于MaxCompute UNNEST使用说明请参考:UNNEST
DDL语法
-- BigQuery
CREATE TABLE orders (
order_id INT64,
items ARRAY<STRUCT<
sku STRING,
qty INT64,
price NUMERIC
>>
);
-- MaxCompute
CREATE TABLE orders (
order_id BIGINT,
items ARRAY<STRUCT<
sku : STRING,
qty : BIGINT,
price : DECIMAL(38, 9)
>>
) TBLPROPERTIES ("table.format.version" = "2");模式 1:标量数组展开
-- BigQuery
SELECT tag
FROM products, UNNEST(tags) AS tag;
-- MaxCompute
SELECT tag
FROM products
JOIN UNNEST(products.tags) AS tag;模式 2:STRUCT 数组展开(最常用)
STRUCT 数组展开后,每个 STRUCT 字段自动成为独立列,与 BigQuery 行为一致。
-- BigQuery
SELECT o.order_id, item.sku, item.qty, item.price
FROM orders o
CROSS JOIN UNNEST(o.items) AS item;
-- MaxCompute
SELECT o.order_id, item.sku, item.qty, item.price
FROM orders o
JOIN UNNEST(o.items) AS item;
-- 若需保留 items 为 NULL 或空数组的行,使用 LEFT JOIN UNNEST(...)。MaxCompute 的 UNNEST 仅展开最外层 STRUCT 字段。若 ARRAY<STRUCT<..., sub STRUCT<...>>> 中存在内层 STRUCT,UNNEST 会把 sub 保留为单列,使用点符号访问其中字段(item.sub.field)。BigQuery 行为相同。
模式 3:JOIN UNNEST(带 ON 条件,MaxCompute 增强)
MaxCompute 的 JOIN UNNEST 支持 ON 等值条件,可以在展开的同时过滤元素,减少中间结果集。BigQuery 不支持此语法。
-- MaxCompute:展开 user 的 allowed_dept_ids,仅保留匹配当前部门的元素
SELECT u.user_id, dept_id AS allowed_dept_id
FROM user_configs u
JOIN UNNEST(u.allowed_dept_ids) AS dept_id
ON dept_id = u.current_dept_id;此语法在权限过滤、标签匹配等场景中比先展开再 WHERE 更高效。
元素位置
BigQuery 的 UNNEST(...) WITH OFFSET AS idx 返回元素位置。MaxCompute 通过 POSEXPLODE 提供该能力:
-- MaxCompute 中 BigQuery WITH OFFSET 的等价写法
SELECT o.order_id, idx, item.sku
FROM orders o
LATERAL VIEW POSEXPLODE(o.items) t AS idx, item;增强嵌套列裁剪
BigQuery 默认对 STRUCT 列执行嵌套列裁剪,查询仅访问 device.os 时,引擎只读取 os 子列,不扫描整个 STRUCT。MaxCompute 也提供增强嵌套列裁剪能力。建议项目级别设置:
SETPROJECT odps.sql.nested.type.enable.enhanced.cp = true;MaxCompute 增强嵌套列裁剪适用于以下复杂类型及其任意嵌套组合:
STRUCT<...>
ARRAY<STRUCT<...>>
MAP<STRING, STRUCT<...>>
多层嵌套组合,如 ARRAY<STRUCT<tags: ARRAY<STRING>, meta: STRUCT<...>>>
生效范围:覆盖 SELECT、WHERE、JOIN、GROUP BY、窗口函数、CTE 和 UNNEST 等场景。
不触发增强裁剪的场景:以下情况引擎无法下推子字段裁剪,会读取完整复杂类型
场景 | 示例 |
SELECT * |
|
引用完整 STRUCT 变量 |
|
TO_JSON() 序列化 |
|
UNNEST 需完整元素 |
|
完整 MaxCompute 增强嵌套列裁剪能力请参考:增强版嵌套列裁剪功能。