生成列

生成列

生成列(Generated Columns)是 Lakehouse 表中的一列,其值由表中的其他列通过表达式自动计算生成。创建时定义计算规则,系统根据规则自动维护列值,无需用户显式插入或更新。常见场景:数据集成同步时在数据库层统一完成字段转换,或将 JSON 字段提取为独立列并建立索引加速查询。

生成列支持两种存储模式:

模式关键字说明
VIRTUAL(默认)省略或写
VIRTUAL
VIRTUAL
不写入 Parquet 文件,查询时动态计算。无额外存储开销。
STORED
STORED
STORED
写入时物化到 Parquet 文件。查询直接读列,优化器可复用,支持 CLUSTER BY。

语法

CREATE TABLE [ IF NOT EXISTS ] table_name ( column_definition, -- VIRTUAL(默认):不写入文件,读时计算 col_name data_type GENERATED ALWAYS AS ( expr ) [VIRTUAL], -- STORED:写入时物化 col_name data_type GENERATED ALWAYS AS ( expr ) STORED, [column_definition, ...] ) [ PARTITIONED BY (column_name column_type | column_name) ];

GENERATED ALWAYS AS (expr):通过表达式

expr
expr
自动生成列的值。表达式支持常量和内置标量确定性函数,不支持以下内容:

  • 非确定性函数:
    current_date()
    current_date()
    、
    current_timestamp()
    current_timestamp()
    、
    rand()
    rand()
    等
  • 聚合函数:
    sum()
    sum()
    、
    count()
    count()
    、
    avg()
    avg()
    等
  • 窗口函数:
    row_number()
    row_number()
    、
    rank()
    rank()
    等
  • 子查询
  • 自引用或循环依赖

支持将生成列作为分区列。

示例:

-- VIRTUAL 生成列(默认):不落盘,读时计算 CREATE TABLE t_virtual ( col1 TIMESTAMP, hour_col INT GENERATED ALWAYS AS (hour(col1)), pt STRING GENERATED ALWAYS AS (date_format(col1, 'yyyy-MM-dd')) ) PARTITIONED BY (pt); -- STORED 生成列:物化写入,支持 CLUSTER BY CREATE TABLE t_stored ( col1 INT, col2 INT GENERATED ALWAYS AS (col1 + 1) STORED ) CLUSTERED BY (col2) SORTED BY (col2) INTO 8 BUCKETS; -- JSON 提取 + 倒排索引(VIRTUAL 典型场景) CREATE TABLE t_json ( id INT, payload JSON, level STRING GENERATED ALWAYS AS (json_extract_string(payload, '$.level')), INDEX idx_level(level) USING INVERTED ) USING PARQUET;

生成列和默认值区别

对比项默认值(DEFAULT)生成列(GENERATED ALWAYS AS)
分区列支持不支持支持
非确定性函数支持(如
current_timestamp()
current_timestamp()
)
不支持
插入时能否指定值可以指定,未指定则用默认值不能指定,完全由表达式决定
列值来源静态常量或非确定性函数其他列的计算结果
ALTER TABLE ADD 后存量行为已有行该列填充为 NULLVIRTUAL:读时按表达式计算,立即可见;STORED:已有行为 NULL(旧文件未物化)

使用限制

  • 插入时不能为生成列显式指定值,否则报错
    insert.generated.column
    insert.generated.column
    。例外:分区字段指定静态值时不报错,但指定值不生效,查询结果仍由表达式决定(Hive 语法兼容)。
  • 不支持实时接口和批量接口写入(含 Studio 数据集成的批量导入和实时写入)。
  • VIRTUAL 生成列不能用于
    CLUSTER BY
    CLUSTER BY
    /
    SORTED BY
    SORTED BY
    ,需改为 STORED 模式。
  • Dynamic Table / 物化视图的列定义中不支持生成列。
  • DROP COLUMN
    DROP COLUMN
    时,若被删除列被其他生成列依赖,会报错
    column.dependency
    column.dependency
    ,需先删除依赖方列。

插入数据

插入时只提供基础列,生成列由系统自动维护:

-- ✅ 正确:只插入 col1,pt 由表达式自动计算 INSERT INTO t_virtual (col1) VALUES (TIMESTAMP '2024-09-26 10:00:00'); -- ❌ 错误:显式指定生成列值,报错 insert.generated.column INSERT INTO t_virtual (col1, pt) VALUES (TIMESTAMP '2024-09-26 10:00:00', '2024-09-26');


添加字段时指定生成列

语法

ALTER TABLE table_name ADD COLUMN column_name data_type GENERATED ALWAYS AS ( expr ) [FIRST | AFTER column_name] [COMMENT column_comment];

说明:

  • 默认只支持添加 VIRTUAL 生成列。添加后,已有数据行在查询时按表达式动态计算,立即可见。
  • 添加 STORED 生成列需开启配置
    cz.sql.alter.table.add.generated.column.enable.stored=true
    cz.sql.alter.table.add.generated.column.enable.stored=true
    ,且已有 Parquet 文件中该列值为 NULL(旧文件未重写)。
  • 不支持修改已有普通列为生成列(
    MODIFY COLUMN
    MODIFY COLUMN
    不支持
    GENERATED ALWAYS AS
    GENERATED ALWAYS AS
    )。

示例

-- 添加 VIRTUAL 生成列(推荐,开箱即用) ALTER TABLE my_table ADD COLUMN year_col INT GENERATED ALWAYS AS (year(event_time)) AFTER event_time; -- 添加后,已有行的 year_col 在查询时自动计算 SELECT id, event_time, year_col FROM my_table LIMIT 5;

联系我们
预约咨询
微信咨询
电话咨询
邮件咨询