为Delta表使用液态聚类

Liquid clustering通过简化数据布局决策来优化查询性能,改进了现有的分区和ZORDER技术。它提供了在不重写现有数据的情况下重新定义聚类列的灵活性,使数据布局能够随着分析需求的变化而逐步演进。

注意

此功能在Delta Lake 3.1.0及以上版本中可用。请参阅限制

什么是液态集群(Liquid Clustering)的用途?

以下是受益于集群化的示例场景:

  • 表经常通过高基数列进行过滤。

  • 数据分布存在显著倾斜的表。

  • 快速增长且需要维护和调优的表。

  • 访问模式随时间变化的表。

  • 表中典型的分区列可能导致分区数量过多或过少的情况。

启用液态聚类

您可以在现有表上或创建表时启用液态聚类。聚类与分区或ZORDER不兼容。启用后,照常运行OPTIMIZE作业以增量式聚类数据。详见How to trigger clustering

要启用液态聚类功能,请在创建表语句中添加CLUSTER BY短语,如下例所示:

注意

在 Delta Lake 3.2 及以上版本中,您可以使用 Python 或 Scala 中的 DeltaTable API 来启用液态集群。

-- Create an empty table
CREATE TABLE table1(col0 int, col1 string) USING DELTA CLUSTER BY (col0);

-- Using a CTAS statement (Delta 3.3+)
CREATE EXTERNAL TABLE table2 CLUSTER BY (col0)  -- specify clustering after table name, not in subquery
LOCATION 'table_location'
AS SELECT * FROM table1;
# Create an empty table
DeltaTable.create()
  .tableName("table1")
  .addColumn("col0", dataType = "INT")
  .addColumn("col1", dataType = "STRING")
  .clusterBy("col0")
  .execute()
// Create an empty table
DeltaTable.create()
  .tableName("table1")
  .addColumn("col0", dataType = "INT")
  .addColumn("col1", dataType = "STRING")
  .clusterBy("col0")
  .execute()

警告

使用液态聚类创建的表启用了ClusteringDomainMetadata表特性(均为写入特性),并使用Delta写入版本7和读取版本1。表协议版本无法降级。参见How does Delta Lake manage feature compatibility?

在 Delta Lake 3.3 及以上版本中,您可以使用以下语法在现有的未分区 Delta 表上启用液态聚类:

ALTER TABLE <table_name>
CLUSTER BY (<clustering_columns>)

重要

默认行为不会对先前写入的数据应用聚类。要强制对所有记录重新聚类,必须使用OPTIMIZE FULL。参见Recluster entire table

选择聚类列

聚类列可以按任意顺序定义。如果两列存在相关性,只需将其中一列添加为聚类列即可。

如果您正在转换现有表,请考虑以下建议:

当前数据优化技术

聚类列建议

Hive风格分区

将分区列用作聚类列。

Z-order索引

使用 ZORDER BY 列作为聚类列。

Hive风格的分区和Z排序

同时使用分区列和 ZORDER BY 列作为聚类列。

生成列以降低基数(例如,时间戳对应的日期)

使用原始列作为聚类列,不要创建生成列。

将数据写入集群表

您必须使用支持ClusteringDomainMetadata表功能的Delta写入客户端。

如何触发聚类

在您的表上使用OPTIMIZE命令,如下例所示:

OPTIMIZE table_name;

Liquid聚类是增量式的,意味着仅在必要时重写数据以容纳需要聚类的数据。已经聚类且具有不同聚类列的数据文件不会被重写。

重新聚类整个表

在Delta Lake 3.3及以上版本中,您可以使用以下语法强制对表中的所有记录进行重新聚类:

OPTIMIZE table_name FULL;

重要

运行OPTIMIZE FULL会根据需要重新聚类所有现有数据。对于之前未在指定列上进行过聚类的大型表,此操作可能需要数小时。

当更改聚类列时运行OPTIMIZE FULL。如果您之前运行过OPTIMIZE FULL且聚类列未发生变化,OPTIMIZE FULL的运行效果将与OPTIMIZE相同。为确保数据布局反映当前聚类列,请始终使用OPTIMIZE FULL

从集群表中读取数据

您可以使用任何Delta Lake客户端读取集群表中的数据。为了获得最佳查询结果,请在查询过滤器中包含聚类列,如下例所示:

SELECT * FROM table_name WHERE clustering_column_name = "some_value";

变更聚类列

你可以随时通过运行ALTER TABLE命令来更改表的聚类列,如下例所示:

ALTER TABLE table_name CLUSTER BY (new_column1, new_column2);

当您更改聚类列时,后续的OPTIMIZE和写入操作将使用新的聚类方法,但现有数据不会被重写。

您也可以通过将列设置为NONE来关闭聚类功能,如下例所示:

ALTER TABLE table_name CLUSTER BY NONE;

将聚类列设置为NONE不会重写已经聚类的数据,但会阻止未来的OPTIMIZE操作使用聚类列。

查看表的集群方式

你可以使用DESCRIBE DETAIL命令来查看表的聚类列,如下例所示:

DESCRIBE DETAIL table_name;

限制

存在以下限制:

  • 只能为已收集统计信息的列指定聚类列。默认情况下,Delta表的前32列会收集统计信息。

  • 您最多可以指定4个聚类列。

重要

在Delta Lake 3.1中,用户需要启用功能标志spark.databricks.delta.clusteredTable.enableClusteringTablePreview才能使用液态聚类。此预览版不支持以下功能:

  • 基于ZCube的增量聚类

  • ALTER TABLE ... CLUSTER BY 用于更改聚类列

  • DESCRIBE DETAIL 用于检查当前的分区列

在Delta Lake 3.2中,预览标志已被移除,并支持上述功能。