在大多数情况下,您并不需要分区键;而在其余大多数情况下,除非是按天分区较为常见的可观测性场景,否则也不需要比按月更细粒度的分区键。切勿使用粒度过细的分区。不要按客户端标识符或名称对数据进行分区,而应将客户端标识符或名称作为 ORDER BY 表达式中的第一列。
PARTITION BY expr 子句指定的。分区键可以是表列中的任意表达式。例如,要指定按月分区,可使用表达式 toYYYYMM(date_column):
合并操作仅适用于分区表达式值相同的数据分区片段。这意味着不应将分区划分得过细 (分区数量不要超过大约一千个) 。否则,由于文件系统中的文件数量过多以及打开的文件描述符过多,
SELECT 查询的性能会很差。visits 表。现在对 system.parts 表执行 SELECT 查询:
partition 列包含分区名称。在此示例中有两个分区:201901 和 201902。您可以使用此列的值,在 ALTER … PARTITION 查询中指定分区名称。
name 列包含分区中各数据分区片段的名称。您可以使用此列,在 ALTER ATTACH PART 查询中指定 part 的名称。
下面来拆解这个 part 的名称:201901_1_9_2_11:
201901是分区名称。1是数据块的最小编号。9是数据块的最大编号。2是 chunk 层级 (即其形成所基于的合并树深度) 。11是变更版本 (如果某个 part 发生过变更) 。
旧类型表的 part 名称为:
20190117_20190123_2_2_0 (最小日期 - 最大日期 - 最小块编号 - 最大块编号 - 层级) 。active 列显示 part 的状态。1 表示活跃;0 表示非活跃。例如,非活跃 part 可能是合并成更大 part 后保留下来的源 part。损坏的数据分区片段也会标记为非活跃。
如您在示例中所见,同一分区存在多个彼此独立的 part (例如 201901_1_3_1 和 201901_1_9_2) 。这意味着这些 part 尚未合并。ClickHouse 会定期合并已插入的数据 part,大约在插入后 15 分钟进行。此外,您还可以使用 OPTIMIZE 查询执行一次非计划合并。示例:
/var/lib/clickhouse/data/<database>/<table>/。例如:
detached 目录包含通过 DETACH 查询从表中分离出的 parts。损坏的 parts 也会被移到这个目录,而不是直接删除。服务器不会使用 detached 目录中的 parts。你可以随时在这个目录中添加、删除或修改数据——只有在运行 ATTACH 查询后,服务器才会感知到这些变更。
请注意,在服务器运行期间,你不能在文件系统中手动更改 parts 集合或其数据,因为服务器无法感知这些变更。对于非复制表,可以在服务器停止时这样做,但不建议这么做。对于复制表,无论在什么情况下都不能更改 parts 集合。
ClickHouse 允许你对分区执行多种操作:删除分区、从一个表复制到另一个表,或创建备份。有关所有操作的列表,请参见 Manipulations With Partitions and Parts 一节。
使用分区键进行 Group By 优化
此类查询的性能很大程度上取决于表布局。因此,这项优化默认未启用。
- 查询涉及的分区数量应足够多 (大于
max_threads / 2) ,否则查询将无法充分利用机器资源 - 分区不应过小,否则批次处理会退化为逐行处理
- 各分区大小应大致相当,这样所有线程承担的工作量才会基本一致
建议在
partition by 子句中的列上应用某种哈希函数,以便将数据均匀分布到各个分区中。allow_aggregate_partitions_independently- 控制是否启用这项优化force_aggregate_partitions_independently- 在从正确性角度可以使用时强制启用该优化,即使内部用于评估其是否划算的逻辑原本会将其禁用max_number_of_partitions_for_independent_aggregation- 对表可拥有的最大分区数设定硬性上限