跳到主要内容
跳到主要内容

选择低基数分区键

A data management technique

分区主要是一种数据管理技术,而不是查询优化工具,虽然它可以在特定工作负载中提高性能,但不应首先用来加速查询;分区键必须小心选择,并明确其影响,只有在与数据生命周期需求或成熟的访问模式一致时才应用。

在 ClickHouse 中,分区根据指定的键将数据组织成逻辑段。这在创建表时使用 PARTITION BY 子句定义,通常用于按时间区间、类别或其他与业务相关的维度对行进行分组。分区表达式的每个唯一值在磁盘上形成自己的物理分区,ClickHouse 为这些值中的每个存储独立的部分。分区提高了数据管理,简化了保留策略,并有助于某些查询模式。

例如,考虑以下带有分区键 toStartOfMonth(date) 的英国支付价格数据集表。

CREATE TABLE uk.uk_price_paid_simple_partitioned
(
  date Date,
  town LowCardinality(String),
  street LowCardinality(String),
  price UInt32
)
ENGINE = MergeTree
ORDER BY (town, street)
PARTITION BY toStartOfMonth(date)

每当一组行插入表时,ClickHouse 创建每个唯一分区键值的新数据部分,而不是创建一个(至少一)包含所有插入行的单一数据部分(如这里所述)。

分区

ClickHouse 服务器首先通过其分区键值 toStartOfMonth(date) 将示例插入中的 4 行拆分成行。然后,对于每个识别的分区,按照通常的步骤处理这些行(① 排序,② 划分到列,③ 压缩,④ 写入磁盘)。

有关分区的更详细解释,我们推荐本指南

启用分区后,ClickHouse 只在分区内合并数据部分,而不跨分区进行合并。我们为上述示例表绘制了这一点:

分区

应用分区

分区是管理 ClickHouse 中大数据集的强大工具,尤其在可观察性和分析用例中。它通过允许与时间或业务逻辑对齐的整个分区在单个元数据操作中被删除、移动或归档,使高效的数据生命周期操作成为可能。这比逐行删除或复制操作显著更快,占用更少资源。分区还与 ClickHouse 特性如 TTL 和分层存储无缝集成,使得在没有自定义编排的情况下实现保留策略或冷热存储策略成为可能。例如,最近的数据可以保留在快速的 SSD 存储中,而较旧的分区则自动转移到更便宜的对象存储中。

虽然分区可以提高某些工作负载的查询性能,但也可能对响应时间产生负面影响。

如果分区键不在主键中,而你又以此进行过滤,用户可能会在使用分区时看到查询性能的提高。 示例请参见这里

相反,如果查询需要跨分区查询,性能可能会受到负面影响,因为总的部分数量较高。因此,在考虑将分区作为查询优化技术之前,用户应理解其访问模式。

总之,用户应主要将分区视为一种数据管理技术。有关管理数据的示例,请参见可观察性用例指南中的"管理数据"和核心概念 - 表分区中的"表分区的用途是什么?"

选择低基数分区键

重要的是,较高的部分数量会对查询性能产生负面影响。因此,如果部分数量超过指定限制,则 ClickHouse 会对插入做出“部分太多”的响应,无论是在总数每个分区中。

为分区键选择正确的基数至关重要。高基数的分区键 - 具有大量不同分区值 - 可能会导致数据部分的急剧增加。由于 ClickHouse 不会跨分区合并部分,因此过多的分区会导致过多未合并的部分,最终触发“部分太多”错误。合并是必要的,用于减少存储碎片并优化查询速度,但使用高基数分区时,这个合并潜力将会丧失。

相比之下,低基数的分区键——具有少于 100 - 1,000 个不同值——通常是最佳选择。它允许高效的部分合并,保持元数据开销低,并避免在存储中创建过多对象。此外,ClickHouse 会自动在分区列上构建 MinMax 索引,这可以显著加速对这些列进行过滤的查询。例如,当表按 toStartOfMonth(date) 分区时,按月份过滤可以让引擎完全跳过无关的分区及其部分。

虽然分区可以提高某些查询模式的性能,但它主要是一项数据管理功能。在许多情况下,跨所有分区查询可能会比使用未分区表更慢,这归因于数据碎片增加和扫描的部分增多。要明智地使用分区,并始终确保所选择的键是低基数并符合你的数据生命周期政策(例如,通过 TTL 进行保留)。如果你不确定分区是否必要,可以先从不使用它开始,随后根据观察到的访问模式进行优化。