分区粒度影响什么
ClickHouse 的 MergeTree 按分区键把数据切成一个个 part,查询时靠分区裁剪跳过无关数据,后台再把同分区的小 part 合并成大 part。分区太粗,单分区数据量大,裁剪效果差;分区太细,part 数量暴涨,合并与元数据开销吃掉查询收益。按月还是按天,取决于数据量与查询条件。
基本信息
| 常用做法 | PARTITION BY toYYYYMM(dt) 按月 |
|---|---|
| 按天场景 | 数据量大且查询按天过滤时 |
| 主要风险 | 分区过细导致 part 数量失控 |
| 监控方式 | 观察 system.parts 里的 part 数量与分区分布 |
| 生命周期 | TTL 可自动删除过期分区 |
典型使用场景
- 明细日志表:按月分区,查询多带时间范围条件
- 高频日查询表:按天分区,让裁剪更精确
- 冷热分离:TTL 把过期分区按规则下沉或删除
- 批量导入:按分区组织批次,避免单个 part 过大
- 容量规划:按分区统计磁盘占用,判断是否需要归档
分区与 TTL 示例
分区与 TTL 示例
CREATE TABLE dw.trade_order
(
dt Date,
order_id String,
pay_amt Decimal(18, 2)
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(dt) -- 按月分区
ORDER BY (dt, order_id) -- 排序键决定稀疏索引
TTL dt + INTERVAL 12 MONTH; -- 超过一年自动删除
-- 观察 part 数量与分区分布
SELECT partition, count() AS parts FROM system.parts
WHERE table = 'trade_order' AND active GROUP BY partition ORDER BY partition;分区键怎么选
| 分区键 | 适用条件 | 后果 |
|---|---|---|
| toYYYYMM(dt) | 多数明细表 | 分区数适中,裁剪有效 |
| toDate(dt) | 日查询多、数据量大 | part 数量增加,需控制写入批次 |
| 高基数列(订单号) | 不应使用 | 分区爆炸,写入与查询异常 |
| 单一枚举列 | 基数低且查询常按它过滤 | 需评估分区数量上限 |
| 不分区 | 小表 | 无裁剪收益,但结构简单 |
part 数量为什么关键
ClickHouse 每次查询都要为涉及的每个 part 建索引与读取线程,part 数量越多,固定开销越大。小批量写入是 part 膨胀的主要来源:每条记录单独插入一次,就会生成一个小 part,后台合并跟不上时,几周内就能累积出成千上万个。写入侧应攒批,并关注后台合并是否落后。
TTL 与分区是配套使用的:TTL 能按时间自动删除或移动过期数据,比手工写清理任务更省心,也避免了删除时长时间占用资源。
分区键选高基数列会导致分区数量随数据增长而爆炸,写入与查询都会出现异常;这类结构问题靠调参数救不回来,只能改表结构并重导数据。