You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ClickHouse中分区键是否需加入PRIMARY KEY或ORDER BY列表?

ClickHouse分区表排序键与主键设计建议

核心结论

不需要将分区键logging_day加入ORDER BY或PRIMARY KEY列表,第一种写法的查询性能更优,第二种写法因冗余字段反而会带来微小的性能损耗。

具体分析

1. 分区键的核心作用

ClickHouse的PARTITION BY logging_day已经将数据按日期做了物理隔离,当执行WHERE logging_day = '2024-04-20'这类查询时,引擎会直接定位到该日期对应的分区,不会扫描其他分区的数据。此时该分区内所有行的logging_day值完全相同,在分区内部再用logging_day做排序或主键索引属于完全冗余的操作。

2. 两种写法的查询流程对比

第一种写法(不含logging_day的排序/主键)

建表语句:

CREATE TABLE IF NOT EXISTS new_table (
  logging_day Date,
  sensor_name String,
  ts DateTime,
  ts_hour DateTime MATERIALIZED toStartOfHour(ts),
)
ENGINE=MergeTree()
PARTITION BY logging_day
ORDER BY (sensor_name, ts_hour, ts)
PRIMARY KEY (sensor_name, ts_hour);

查询流程:

  • 第一步:通过logging_day过滤出目标分区,仅扫描该分区内的数据。
  • 第二步:在分区内,利用主键sensor_name, ts_hour快速定位到sensor_name='foo'且ts_hour='2024-04-20 13:00:00'的连续行范围(因ORDER BY与主键匹配,数据按该顺序连续存储),直接读取对应数据即可。

第二种写法(含logging_day的排序/主键)

建表语句:

CREATE TABLE IF NOT EXISTS new_table (
  logging_day Date,
  sensor_name String,
  ts DateTime,
  ts_hour DateTime MATERIALIZED toStartOfHour(ts),
)
ENGINE=MergeTree()
PARTITION BY logging_day
ORDER BY (logging_day, sensor_name, ts_hour, ts)
PRIMARY KEY (logging_day, sensor_name, ts_hour);

查询流程:

  • 第一步:同样通过logging_day过滤出目标分区。
  • 第二步:在分区内,主键的第一个字段logging_day值完全一致,实际还是靠sensor_name和ts_hour定位数据。由于主键多了一个冗余字段,索引的存储体积更大,会微小增加索引查找的开销,无法带来任何性能提升。

3. 额外注意事项

  • 原建表语句存在语法错误:ts DateTime行末尾缺少逗号,需要修正后才能正常执行。
  • 即便查询条件中没有logging_day,第一种写法的索引更紧凑,整体性能依然优于第二种写法。

内容的提问来源于stack exchange,提问作者ningl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 06:03:25