Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
重要
此功能目前以公共预览版提供。
Delta Lake 支持生成的列,这些列是一种特殊类型的列,其值基于用户指定的函数在 Delta 表中的其他列上自动生成。 当您向一个包含生成列的表中写入数据且未显式提供这些列的值时,Delta Lake 会自动计算这些值。 例如,可以从时间戳列自动生成日期列(用于按日期对表进行分区);对表进行的任何写入都只需为时间戳列指定数据。 但是,如果显式为这些表提供值,则这些值必须满足约束(<value> <=> <generation expression>) IS TRUE,否则写入将失败并出现错误。
重要
使用生成的列创建的表的表写入器协议版本高于默认版本。 请参阅 Delta Lake 功能兼容性和协议 ,了解表协议版本控制以及具有更高版本的表协议版本意味着什么。
创建包含生成的列的表
下面的示例介绍如何使用生成的列创建表:
SQL
CREATE TABLE default.people10m (
id INT,
firstName STRING,
middleName STRING,
lastName STRING,
gender STRING,
birthDate TIMESTAMP,
dateOfBirth DATE GENERATED ALWAYS AS (CAST(birthDate AS DATE)),
ssn STRING,
salary INT
)
Python
DeltaTable.create(spark) \
.tableName("default.people10m") \
.addColumn("id", "INT") \
.addColumn("firstName", "STRING") \
.addColumn("middleName", "STRING") \
.addColumn("lastName", "STRING", comment = "surname") \
.addColumn("gender", "STRING") \
.addColumn("birthDate", "TIMESTAMP") \
.addColumn("dateOfBirth", DateType(), generatedAlwaysAs="CAST(birthDate AS DATE)") \
.addColumn("ssn", "STRING") \
.addColumn("salary", "INT") \
.execute()
Scala(编程语言)
DeltaTable.create(spark)
.tableName("default.people10m")
.addColumn("id", "INT")
.addColumn("firstName", "STRING")
.addColumn("middleName", "STRING")
.addColumn(
DeltaTable.columnBuilder("lastName")
.dataType("STRING")
.comment("surname")
.build())
.addColumn("lastName", "STRING", comment = "surname")
.addColumn("gender", "STRING")
.addColumn("birthDate", "TIMESTAMP")
.addColumn(
DeltaTable.columnBuilder("dateOfBirth")
.dataType(DateType)
.generatedAlwaysAs("CAST(dateOfBirth AS DATE)")
.build())
.addColumn("ssn", "STRING")
.addColumn("salary", "INT")
.execute()
生成的列像普通列一样存储。 也就是说,它们会占用存储空间。
以下限制适用于生成的列:
- 生成表达式可以使用 Spark 中的任何 SQL 函数,这些函数在给定相同的参数值时始终返回相同的结果,但以下类型的函数除外:
- 用户定义的函数。
- 聚合函数。
- 窗口函数。
- 返回多行的函数。
只要有以下表达式之一定义了分区列,Delta Lake 就能为查询生成分区筛选器:
注意
Databricks Runtime 10.4 LTS 及更低版本中需要 Photon。 Databricks Runtime 11.3 LTS 及更高版本中不需要 Photon。
-
CAST(col AS DATE),col的类型为TIMESTAMP。 -
YEAR(col),col的类型为TIMESTAMP。 -
YEAR(col), MONTH(col)定义的两个分区列的类型分别为col和TIMESTAMP。 -
YEAR(col), MONTH(col), DAY(col)定义的三个分区列,col的类型为TIMESTAMP。 -
YEAR(col), MONTH(col), DAY(col), HOUR(col)定义的四个分区列,col的类型为TIMESTAMP。 -
SUBSTRING(col, pos, len),col的类型为STRING -
DATE_FORMAT(col, format),col的类型为TIMESTAMP。- 只能使用以下模式的日期格式:
yyyy-MM和yyyy-MM-dd-HH。 - 在 Databricks Runtime 10.4 LTS 及更高版本中,还可以使用以下模式:
yyyy-MM-dd。
- 只能使用以下模式的日期格式:
如果某个分区列是由前面提到的表达式之一定义的,并且查询使用生成表达式的基础列过滤数据,那么 Delta Lake 会分析基础列与生成列之间的关系,并在可能的情况下,根据生成的分区列来设置分区过滤器。 例如,给定以下表格:
CREATE TABLE events(
eventId BIGINT,
data STRING,
eventType STRING,
eventTime TIMESTAMP,
eventDate date GENERATED ALWAYS AS (CAST(eventTime AS DATE))
)
PARTITIONED BY (eventType, eventDate)
然后运行以下查询:
SELECT * FROM events
WHERE eventTime >= "2020-10-01 00:00:00" <= "2020-10-01 12:00:00"
则 Delta Lake 会自动生成一个分区筛选器,这样,即使未指定分区筛选器,上述查询也只会读取分区 date=2020-10-01 中的数据。
例如,再给出一个例子,考虑下表:
CREATE TABLE events(
eventId BIGINT,
data STRING,
eventType STRING,
eventTime TIMESTAMP,
year INT GENERATED ALWAYS AS (YEAR(eventTime)),
month INT GENERATED ALWAYS AS (MONTH(eventTime)),
day INT GENERATED ALWAYS AS (DAY(eventTime))
)
PARTITIONED BY (eventType, year, month, day)
然后运行以下查询:
SELECT * FROM events
WHERE eventTime >= "2020-10-01 00:00:00" <= "2020-10-01 12:00:00"
则 Delta Lake 会自动生成一个分区筛选器,这样,即使未指定分区筛选器,上述查询也只会读取分区 year=2020/month=10/day=01 中的数据。
可以使用 EXPLAIN 子句并检查提供的计划,以查看 Delta Lake 是否自动生成任何分区筛选器。
在 Delta Lake 中使用标识列
重要
在 Delta 表格上声明标识列会禁用并发事务。 仅在不需要对目标表进行并发写入的用例中使用标识列。
Delta Lake 标识列是一种生成的列,将为插入到表中的每条记录分配唯一值。 以下示例演示了在 create table 语句期间声明标识列的基本语法:
SQL
CREATE TABLE table_name (
id_col1 BIGINT GENERATED ALWAYS AS IDENTITY,
id_col2 BIGINT GENERATED ALWAYS AS IDENTITY (START WITH -1 INCREMENT BY 1),
id_col3 BIGINT GENERATED BY DEFAULT AS IDENTITY,
id_col4 BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH -1 INCREMENT BY 1)
)
Python
from delta.tables import DeltaTable, IdentityGenerator
from pyspark.sql.types import LongType
DeltaTable.create()
.tableName("table_name")
.addColumn("id_col1", dataType=LongType(), generatedAlwaysAs=IdentityGenerator())
.addColumn("id_col2", dataType=LongType(), generatedAlwaysAs=IdentityGenerator(start=-1, step=1))
.addColumn("id_col3", dataType=LongType(), generatedByDefaultAs=IdentityGenerator())
.addColumn("id_col4", dataType=LongType(), generatedByDefaultAs=IdentityGenerator(start=-1, step=1))
.execute()
Scala(编程语言)
import io.delta.tables.DeltaTable
import org.apache.spark.sql.types.LongType
DeltaTable.create(spark)
.tableName("table_name")
.addColumn(
DeltaTable.columnBuilder(spark, "id_col1")
.dataType(LongType)
.generatedAlwaysAsIdentity().build())
.addColumn(
DeltaTable.columnBuilder(spark, "id_col2")
.dataType(LongType)
.generatedAlwaysAsIdentity(start = -1L, step = 1L).build())
.addColumn(
DeltaTable.columnBuilder(spark, "id_col3")
.dataType(LongType)
.generatedByDefaultAsIdentity().build())
.addColumn(
DeltaTable.columnBuilder(spark, "id_col4")
.dataType(LongType)
.generatedByDefaultAsIdentity(start = -1L, step = 1L).build())
.execute()
注意
Databricks Runtime 16.0 及更高版本提供用于标识列的 Scala 和 Python API。
若要查看用于创建包含标识列的表的所有 SQL 语法选项,请参阅 CREATE TABLE [USING]。
可以选择指定以下内容:
- 起始值。
- 步长,可以是正值或负值。
起始值和步长的默认值均为1。 不能指定步长 0。
标识列分配的值是唯一的,朝指定步长的方向按指定步长大小的倍数递增,但不保证是连续的。 例如,如果起始值为 0,步长为 2,则所有值都是正偶数,但有些偶数可能会被跳过。
使用子句 GENERATED BY DEFAULT AS IDENTITY 时,插入操作可以为标识列指定值。 将该子句修改为 GENERATED ALWAYS AS IDENTITY,以替代手动设置值的功能。
标识列仅支持 BIGINT 类型,如果分配的值超过 BIGINT 支持的范围,则操作将会失败。
若要了解如何将标识列值与数据同步,请参阅 ALTER TABLE ...COLUMN 子句。
CTAS 和标识列
在使用 CREATE TABLE table_name AS SELECT (CTAS) 语句时,不能定义架构、标识列约束或任何其他表规范。
要使用标识列创建新表并使用现有数据填充该表,请执行以下操作:
创建具有正确架构的表,包括标识列定义和其他表属性。
运行
INSERT操作。
以下示例使用 DEFAULT 关键字来定义标识列。 如果插入到表中的数据包括标识列的有效值,则使用这些值。
CREATE OR REPLACE TABLE new_table (
id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 5),
event_date DATE,
some_value BIGINT
);
-- Inserts records including existing IDs
INSERT INTO new_table (id, event_date, some_value)
SELECT id, event_date, some_value FROM old_table;
-- Insert records and generate new IDs
INSERT INTO new_table (event_date, some_value)
SELECT event_date, some_value FROM new_records;
标识列限制
使用标识列时存在以下限制:
- 启用了标识列的表不支持并发事务。
- 不能按标识列对表进行分区。
- 不能使用
ALTER TABLE来ADD、REPLACE或CHANGE标识列。 - 不能更新现有记录中身份列的值。
注意
若要更改现有记录的 IDENTITY 值,必须删除该记录并将其 INSERT 为新记录。
生成的列和列掩码
生成的列无法引用应用了列掩码的列,因为生成的值将显示掩码保护的基础数据。 这会引发错误,查询失败。 请参阅 行筛选器和列掩码。
下面是错误的示例:
无法创建表达式引用遮罩列的生成列。 引发 COLUMN_MASKS_GENERATED_COLUMN_UNSUPPORTED。
CREATE TABLE tbl ( a INT MASK masking_function, generated_col INT GENERATED ALWAYS AS (a + 1) ) USING DELTA;不能将列掩码应用于已被生成列引用的列。 引发COLUMN_MASKS_REFERENCED_BY_GENERATED_COLUMN.ADD_MASK。
CREATE TABLE tbl ( a INT, generated_col INT GENERATED ALWAYS AS (a + 1) ) USING DELTA; ALTER TABLE tbl ALTER COLUMN a SET MASK masking_function;从一个包含掩码列且生成列引用了该掩码列的表中读取的操作也将被阻止。 引发 COLUMN_MASKS_REFERENCED_BY_GENERATED_COLUMN.READ_BLOCKED。
若要解决所有这些错误,必须重新设计表,以便生成的列和掩码列不会重叠。