选择低基数分区键
分区主要是一种数据管理技术,而不是查询优化工具。虽然它可以提高特定工作负载的性能,但不应将其作为加速查询的首要机制。必须仔细选择分区键,清楚地了解其影响,并且仅在与数据生命周期需求或明确的访问模式相符时才应用分区。
在 ClickHouse 中,分区根据指定的键将数据组织成逻辑段。这使用表创建时的 PARTITION BY 子句定义,通常用于按时间间隔、类别或其他与业务相关的维度对行进行分组。分区表达式的每个唯一值在磁盘上形成其自己的物理分区,ClickHouse 为这些值的每一个都存储单独的数据部分。分区可以改善数据管理,简化保留策略,并有助于某些查询模式。
例如,考虑以下英国房价数据集表,其分区键为 toStartOfMonth(date)。
每当将一组行插入到表中时,ClickHouse 不会创建(至少)一个包含所有插入行的单个数据部分(如 此处 所述),而是为插入行中的每个唯一分区键值创建一个新的数据部分。
ClickHouse 服务器首先根据分区键值 toStartOfMonth(date) 将示例插入中的 4 行行拆分为各自的分区。然后,对于每个识别出的分区,行将按照 通常 的方式处理,执行几个顺序步骤(① 排序,② 拆分为列,③ 压缩,④ 写入磁盘)。
有关分区的更详细说明,我们建议您阅读 本指南。
启用分区后,ClickHouse 仅 合并 分区内的,而不是跨分区的数据块。我们为上面的示例表绘制了示意图
分区的应用
分区是在 ClickHouse 中管理大型数据集的强大工具,尤其是在可观察性和分析用例中。它通过允许整个分区(通常与时间或业务逻辑对齐)以单个元数据操作进行删除、移动或存档,从而实现高效的数据生命周期操作。这比基于行的删除或复制操作快得多且资源消耗更少。分区还可以与 ClickHouse 功能(如 TTL 和分层存储)无缝集成,从而可以实现保留策略或热/冷存储策略,而无需自定义编排。例如,可以将最近的数据保存在快速的 SSD 支持的存储上,而将较旧的分区自动移动到更便宜的对象存储中。
虽然分区可以提高某些工作负载的查询性能,但它也可能对响应时间产生负面影响。
如果分区键不在主键中,并且您正在按其进行过滤,用户可能会看到分区带来的查询性能提升。请参阅 此处 以获取示例。
相反,如果查询需要跨分区查询,由于总部分数增加,性能可能会受到负面影响。因此,用户应了解他们的访问模式,然后再考虑将分区作为查询优化技术。
总而言之,用户应首先将分区视为一种数据管理技术。有关数据管理示例,请参阅可观察性用例指南中的 “管理数据” 以及核心概念 - 表分区中的 “表分区用于什么?”。
选择低基数分区键
重要的是,更多的部分数会对查询性能产生负面影响。因此,如果部分数超过指定的限制(无论是 总数 还是 每个分区),ClickHouse 将对插入做出响应,并显示 “部分过多” 错误。
为分区键选择正确的 基数 至关重要。高基数分区键(即不同分区值的数量很大)会导致数据部分激增。由于 ClickHouse 不会在分区之间合并部分,因此过多的分区会导致过多的未合并部分,最终触发“部分过多”错误。 合并对于减少存储碎片和优化查询速度至关重要,但对于高基数分区,这种合并潜力丧失了。
相反,低基数分区键(具有少于 100-1,000 个不同值)通常是最佳选择。它可以实现高效的部分合并,保持较低的元数据开销,并避免存储中创建过多的对象。此外,ClickHouse 会自动在分区列上构建 MinMax 索引,这可以显著加快对这些列进行过滤的查询速度。例如,当表按 toStartOfMonth(date) 分区时,按月份进行过滤允许引擎完全跳过不相关的分区及其部分。
虽然分区可以提高某些查询模式的性能,但它主要是一种数据管理功能。在许多情况下,跨所有分区查询可能比使用非分区表慢,因为数据碎片增加且扫描的部分更多。谨慎使用分区,并始终确保所选键的基数较低,并且与您的数据生命周期策略(例如,通过 TTL 进行保留)相符。如果您不确定是否需要分区,可以先不使用它,然后根据观察到的访问模式进行优化。