分区键决定什么
分区键把数据切成互相独立的目录:同一个分区的数据单独存放,删除与移动都以分区为单位。查询时对分区键的过滤可以整块跳过分区,日常运维也能用一条 DROP PARTITION 秒级清掉历史数据,因此分区设计同时影响查询效率与运维成本。
基本信息
| 常用写法 | toYYYYMM(ts) 按月、toDate(ts) 按天、tuple(region, toYYYYMM(ts)) 组合 |
|---|---|
| 收益 | 分区裁剪减少扫描,DROP PARTITION 可秒级清理历史数据 |
| 代价 | 分区数量过多会让元数据、合并与查询开销一起上升 |
| 分区键类型 | 表达式结果最好是整数或日期,避免浮点与 Nullable |
| 查看方式 | system.parts 按 partition 分组统计行数与体积 |
典型使用场景
- 按时间清理:用 DROP PARTITION 替代逐行删除
- 冷热分层:按分区把老数据整体搬到冷存储
- 查询加速:时间过滤直接跳过分区目录
- 数据重算:只对有问题的分区重新导入
- 容量分析:按分区看数据量与增长趋势
常用操作
常用操作
-- 建表时按月分区
CREATE TABLE events
(
ts DateTime,
user_id UInt64,
action LowCardinality(String)
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (user_id, ts);
-- 查看分区及大小
SELECT partition, rows, formatReadableSize(bytes_on_disk) AS size
FROM system.parts
WHERE table = 'events' AND active
ORDER BY partition;
-- 按分区删除历史数据,远比 DELETE 快
ALTER TABLE events DROP PARTITION '202301';
-- 用执行计划确认过滤是否触发了分区裁剪
EXPLAIN indexes = 1 SELECT count() FROM events WHERE toYYYYMM(ts) = 202610;分区粒度对照
| 分区键 | 粒度 | 适用 |
|---|---|---|
| toYYYYMM(ts) | 按月 | 保留期长、数据量中等的表 |
| toDate(ts) | 按天 | 保留期短、需要按天重算的表 |
| tuple(region, toYYYYMM(ts)) | 组合 | 按地域与月份双维度管理 |
| 按秒或按高基数列 | 过细 | 分区数量失控,合并与元数据开销激增 |
按月分区适合保留期长的表,按天分区适合保留期短或需要按天重算的表,两者也可以组合成 tuple 键;关键是让分区总数维持在可维护的量级。
对分区表达式直接过滤(例如 toYYYYMM(ts) = 202610)最容易命中裁剪;写成时间范围的形式通常也能裁剪,不确定时用 EXPLAIN indexes = 1 看一眼实际跳过情况。