Append Delta Table - Data Evolution 列级更新

更新时间:
复制 MD 格式

Data Evolution 是 MaxCompute 针对 Append Delta Table 推出的列级更新能力。在大规模列级更新等场景下,通过 UPDATE ... EVOLVE COLUMNS 只更新指定列,被更新列的数据写入独立文件,读取时与原始数据自动合并,避免重写整个数据文件带来的 I/O 开销。

功能介绍

Append Delta Table 的普通 UPDATE 语句会重写匹配行的数据文件。Data Evolution 模式将列级别的更新数据写入独立的数据文件,读取时把多个列文件与原始文件按行合并输出,因此在频繁新增列、需要对历史数据回填新列的链路中,可以显著减少写链路的数据开销。

适用场景

  • 加列后回填

    ALTER TABLE ADD COLUMNS 新增列后,使用 EVOLVE COLUMNS 对历史行回填新列取值,未匹配行保持 NULL。整表数据文件无需重写。

  • 特征工程与特征列演进

    特征表需要频繁新增特征列,在模型迭代过程中反复调整少数特征列的取值,每次只写入被调整的列。

  • 派生列迭代计算

    标签列、汇总列等派生字段依赖同表其他列计算,SET 中引用目标表已有列即可原地重算。

  • 高频列级更新

    宽表中只更新少数列时,避免整文件重写带来的写放大和存储开销。

使用限制

  • UPDATE ... EVOLVE COLUMNS 仅对开启 data.evolution.enable 的表可用,未开启时语句报错。

  • 开启 Data Evolution 的表不支持 Time Travel 查询。

  • 开启 Data Evolution 的表不支持与 CLUSTERED BY 聚簇子句同时建表。

  • 分区表执行 EVOLVE COLUMNS 时,WHERE 中须指定分区过滤条件,否则按全分区扫描被拦截。

  • 仅 WHERE 或关联条件匹配的行被更新,其余行保留原值。

  • 同一列多次执行 EVOLVE COLUMNS 时,后一次结果覆盖前一次

命令格式

UPDATE <table_name> [[AS] <alias>] EVOLVE COLUMNS
SET <col1_name> = <value1> [, <col2_name> = <value2> ...]
[FROM <source_table> [[AS] <source_alias>]]
[WHERE <where_condition>];
  • 表属性需设置 'table.format.version'='2' 且 'data.evolution.enable'='true'。分区表同样支持。

  • EVOLVE COLUMNS 固定位于目标表(及其别名)之后、SET 之前。

  • SET 赋值支持常量、源表列或表达式,表达式中可引用目标表的其他列。

参数说明

参数

是否必选

说明

table_name

必填

待执行更新的目标表名称。需开启 'table.format.version'='2''data.evolution.enable'='true'

alias

可选

目标表别名。SET 中以 <alias>.<col_name> 引用目标列

col1_name、col2_name

必填

待更新的列名称,至少指定一个。支持同时指定多列。

value1、value2

必填

列的新取值。可为常量、源表列或表达式(表达式中可引用目标表其他列)

source_table

可选

FROM 子句指定的源表。

  • 有源表时按关联条件匹配目标行

  • 无源表时按目标表自身条件更新

source_alias

可选

源表别名

where_condition

可选

WHERE 子句,筛选满足条件的行。不带 WHERE 子句时更新表中所有行;分区表需在此指定分区过滤条件

每条 UPDATE ... EVOLVE COLUMNS 语句都会使用计算资源并产生费用,建议用批量方式更新,避免提交大量只更新单行的作业。

使用方法

步骤一:建表并开启 Data Evolution

创建 Append Table 时在 TBLPROPERTIES 中开启 data.evolution.enable。分区表写法相同,只需增加 PARTITIONED BY 子句:

CREATE TABLE user_events (
    id  BIGINT,
    v1  STRING,
    v2  STRING
) TBLPROPERTIES ('table.format.version'='2', 'data.evolution.enable'='true');

步骤二:加列后回填新列

新增列后,使用不携带 FROM 的形式按目标表自身条件回填:

ALTER TABLE user_events ADD COLUMNS (v3 STRING);

UPDATE user_events AS t EVOLVE COLUMNS
SET t.v3 = 'backfill_v3'
WHERE t.id IN (1, 2);

步骤三:关联源表更新

携带 FROM 子句时,按关联条件匹配目标行,并将源表取值写入目标列:

UPDATE user_events AS t EVOLVE COLUMNS
SET t.v1 = s.v1
FROM user_events_src AS s
WHERE t.id = s.id;

完整示例

-- Step 1: 创建开启 Data Evolution 的 Append Table
CREATE TABLE user_events (
    id  BIGINT,
    v1  STRING,
    v2  STRING
) TBLPROPERTIES ('table.format.version'='2', 'data.evolution.enable'='true');

-- Step 2: 写入基础数据
INSERT INTO user_events (id, v1, v2) VALUES (1, 'a1', 'b1'), (2, 'a2', 'b2'), (3, 'a3', 'b3');

-- Step 3: 新增列并回填部分行
ALTER TABLE user_events ADD COLUMNS (v3 STRING);

UPDATE user_events AS t EVOLVE COLUMNS
SET t.v3 = 'backfill_v3'
WHERE t.id IN (1, 2);

-- Step 4: 关联源表更新 v1
CREATE TABLE user_events_src (id BIGINT, v1 STRING);
INSERT INTO user_events_src VALUES (2, 'a2_new'), (3, 'a3_new');

UPDATE user_events AS t EVOLVE COLUMNS
SET t.v1 = s.v1
FROM user_events_src AS s
WHERE t.id = s.id;

-- Step 5: 查询验证
SELECT id, v1, v2, v3 FROM user_events ORDER BY id;

返回结果:

+----+--------+----+-------------+
| id | v1     | v2 | v3          |
+----+--------+----+-------------+
| 1  | a1     | b1 | backfill_v3 |
| 2  | a2_new | b2 | backfill_v3 |
| 3  | a3_new | b3 | NULL        |
+----+--------+----+-------------+

id=3 的行未匹配回填条件,新列 v3 为 NULL;v1 在 Step 4 中被源表取值覆盖。