ClickHouse 建表:排序键和分区键到底怎么定,一张日志表的完整设计过程

简介: 把 MySQL 的建表习惯原样搬到 ClickHouse,第一周多半会撞上查询慢和 Too many parts——根子都在排序键和分区键。这篇文章把稀疏索引、排序键三条硬规则、分区键的边界,和一张日志表的完整建表串起来讲清楚。

把 MySQL 的建表习惯原样搬到 ClickHouse,第一周大概率会撞两件事:查询慢得不像"列存分析引擎",以及日志里躺着一条 Too many parts。

这两件事看着不相干,根子是同一个:ClickHouse 的"主键"和"分区"跟 OLTP 里名字一样的那两个东西,机制完全不同。下面把排序键、分区键、稀疏索引拆开讲,最后落到一张日志表的完整建表语句上。

一、先把三个名字拆开

MergeTree 家族建表时会碰到三个键,作用完全不重叠:

名称 写在 DDL 的位置 决定什么 不写会怎样
排序键 ORDER BY (a, b, c) 每个 data part 内部数据的物理排列顺序,同时也是稀疏索引的生成依据 MergeTree 必填,没有默认值
主键 PRIMARY KEY (...) 键值的稀疏索引;必须是排序键的前缀 不指定时默认等于排序键
分区键 PARTITION BY toYYYYMM(t) 把数据切成一堆互相独立的 part 集合 不写就是单分区,全部数据挤在一起

两个高频误解,官方文档里专门点名过:

误解一:主键唯一。 主键不强制唯一,重复键值的行可以共存,不报错;要唯一性只能自己做去重(ReplacingMergeTree 也只是"最终"去重,不是约束)。

误解二:主键等于索引。 主键只负责"按这个顺序落盘"。在 ORDER BY (service_name, event_time) 的表上只按 event_time 过滤,首列没命中,稀疏索引基本帮不上忙,照样得扫大量数据块。

阿里云 ClickHouse 产品优势:高性能、企业级内核、开箱即用、全面运维体系

二、稀疏索引:为什么它敢扛 PB 级

OLTP 的 B+Tree 是稠密索引,每一行都有一条索引项。ClickHouse 反过来:它按 ORDER BY 把数据排好序落盘,然后每 8192 行(一个 granule,默认粒度)只记一条键值,形成一份极轻量的稀疏索引。

这份索引小到可以整个装进内存。查询时的路径是这样:

  1. 用稀疏索引在内存里二分,定位可能命中的 granule;
  2. 只在这些 granule 里做顺序扫描 + 表达式过滤,其余 granule 直接跳过。

这个设计是明确的取舍:牺牲单行点查,换高吞吐的范围扫描和列级压缩。拿它当 KV 用、一条一条 WHERE id = ? 地查,性能会很难看;反过来,扫几亿行做聚合,它能把 MySQL 甩开两三个数量级。

三条直接推论,后面所有设计原则都由它们推出来:

  • 过滤列不在排序键里 → 索引裁剪失效 → 全表扫;
  • 列序不按基数升序 → 相同值分散在不同 granule → 压缩率掉下来;
  • 排序键列太多 → 索引体积变大、排序开销上升 → 写入变慢。

三、排序键怎么选:三条硬规则

官方主键设计文档给的建议可以压成三句话:

规则一:只放高频过滤列,通常不超过三列。 判断标准很实在——这一列会不会出现在 WHERE、GROUP BY、JOIN 条件里?不会就别放。曾见过把十个业务字段一股脑塞进 ORDER BY 的表,索引膨胀、写入变慢,查询一点没快。

规则二:首列要"高频 + 高筛选率"。 首列决定能裁掉多少 granule,影响力最大。日志场景几乎总是时间字段:绝大多数查询都带时间范围,把时间放第一位,范围外的 granule 直接被跳过。

规则三:后面的列按基数升序,低基数在前。 这样相同值连续落盘,压缩算法才能有效去重。反例是 ORDER BY (user_id, country)——user_id 基数极高,把 country 打散到几乎每个 granule,压缩率白白损失。

同一个日志需求,两种写法:

-- 正例:首列时间做裁剪,service_name 基数中等放第二,level 基数最低放最后
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_time)
ORDER BY (event_time, service_name, log_level)

-- 反例:首列是低基数的 level,裁剪能力极差;user_id 前置又把压缩率打散
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_time)
ORDER BY (log_level, user_id, event_time)

反例不是"跑不起来",是"跑得起来但一直很慢",这种问题最难被发现——它不报错,只是每次查询都多扫十倍数据。

四、分区键:它是数据管理工具,不是加速开关

这是最容易搞反的一点。官方文档的原话是:分区主要用于数据过期、冷热分层、批量删除,而不是首选的查询优化工具。跨全部分区查询甚至可能比不分区更慢——part 更碎,要扫的 part 更多。

选分区键的四条:

① 基数要低,分区总数控制在 100~1000。 这是硬区间。分区过多会让元数据、文件句柄、内存一起吃不消,更致命的是合并只在分区内部进行——分区一多,part 合不上,小 part 越堆越多。

② 按时间分区,按月或按天。 用 toYYYYMM(event_time) 或 toDate(event_time),天然对齐"按月归档、按月清理"的运维动作。

③ 别拿高基数字段分区,也别切太细。 user_id、order_id、device_id 一个值一个分区,分区数直接爆炸;toYYYYMMDDhhmm(event_time) 一天 1440 个分区,一年五十多万个,等于自己造事故。典型报错就是:

DB::Exception: Too many parts (N). Merges are processing significantly slower than inserts

④ 用原始字段或简单表达式。 别套复杂函数,否则分区裁剪用不上。

分区真正的价值在删除路径上:

删除方式 扫描量 耗时量级 空间回收
ALTER TABLE ... DELETE WHERE 扫全表定位行,生成 mutation 分钟到小时级,随数据量线性增长 后台异步,需等 merge
DROP PARTITION 202609 直接删目录,不扫数据 秒级 立即释放

按月分区之后,清理三个月前的数据就一句 ALTER TABLE logs DROP PARTITION 的事;不分区的话,只能上 ALTER TABLE DELETE,几亿行扫下来,磁盘 IO 先撑不住。

阿里云 ClickHouse 产品功能:湖仓一体实时数据分析与资源队列

五、合起来:一张日志表的完整设计

需求很普通:按天查询、按服务名过滤、保留 6 个月、要能快速删历史。

CREATE TABLE logs
(
    event_time   DateTime,
    service_name LowCardinality(String),
    log_level    LowCardinality(String),
    trace_id     String,
    message      String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_time)        -- 按月分区:对齐 6 个月保留策略
ORDER BY (event_time, service_name)      -- 排序键:时间先裁 granule,服务名在块内过滤
TTL event_time + INTERVAL 6 MONTH DELETE -- 结合分区,过期数据自动清
SETTINGS index_granularity = 8192;

查一条典型语句:

SELECT log_level, count()
FROM logs
WHERE service_name = 'order'
  AND event_time >= now() - INTERVAL 1 DAY
GROUP BY log_level;

验证裁剪有没有生效,不要凭感觉,直接看执行计划:

EXPLAIN indexes = 1
SELECT count() FROM logs
WHERE service_name = 'order'
  AND event_time >= now() - INTERVAL 1 DAY;

输出里重点看两处:Partitions 的选中比例(是不是只扫了 1 个月而不是 6 个)、PrimaryKey 的 Granules 比例(示意形如 12/1440)。两个都是个位数百分比说明设计到位;Granules 接近全选,说明排序键没覆盖住这个查询。

排序键永远是取舍:如果业务里"只按服务名、不带时间"的查询占了大头,就把 service_name 提到首位,代价是时间范围裁剪和压缩率。分区键则尽量只服务生命周期,别跟着查询跑。

六、跳数索引:排在最后才考虑

排序键覆盖不到的过滤列,可以用跳数索引(data skipping index)补,比如 bloom_filter、minmax、set。但它有明确的优先级:

  1. 先改排序键(覆盖高频过滤列);
  2. 再想预计算——投影(Projection)或物化视图,把高频聚合先算好;
  3. 最后才是跳数索引。

原因是跳数索引有双重开销:写入时要构建索引(拖慢写入),查询时要先评估索引再去扫 part(索引没筛掉东西就是纯亏)。官方给的判定标准很硬——索引要能跳过 90% 以上的数据块才有意义。所以别一上来给五个列建五个索引,那通常只是把表结构搞复杂、把写入搞慢。

七、写入侧:part 数量是另一条命门

Too many parts 不只来自分区设计,也来自写入方式。每次 INSERT 都生成新的 part,合并是后台异步做的。如果每秒来一次几百行的小批量写,part 产生速度就会超过合并速度,最终把表卡住。

实践上就三条:攒批写(零散记录在应用侧或消息队列里聚合,单批做到几千到十万行量级,按单行大小和内存算)、控制写入并发(多客户端狂写同一张表,等于人为制造小 part)、别频繁小批量 mutation(ALTER UPDATE/DELETE 每次都会重写 part)。分区键基数一高,每次插入要写的 part 也跟着涨——这两个问题同一个源头。

八、版本与账单:先想清楚要哪一种

维度 社区兼容版 企业版
架构 计算存储耦合,节点对等,跑在 ECS + 云盘上 存算分离,OSS 共享存储,Serverless 弹性
弹性 手动变配、平滑水平扩容 按负载秒级自动弹升弹降,扩缩容不迁数据
内核 22.8 / 21.8 / 20.8 等 23.8(含 Lightweight Update/Delete、ClickHouse Keeper)
计费 计算 + 存储,包年包月或按量 计算按 CCU 小时、存储按 GB 小时,全按量

社区兼容版有两个计费细节要提前知道:存储按"购买容量"收费,不按实际占用——买 100GB 只用了 20GB,照样按 100GB 计费,别为"以后可能要用"一次买大;备份免费额度 = 100% × 集群存储空间,超出部分才按量,冷热分层需先手动开通冷存储。

规格上,社区兼容版标准型 8 核 32GB 单副本约 ¥1473.40/月、双副本约 ¥2946.80/月(官网折扣价,价格与活动以官方页面实时展示为准)。产品能力与计费入口都在 云数据库 ClickHouse 页面上。

九、上线前按这张表过一遍

检查项 合格标准
排序键列数 ≤3 列,且都是高频过滤列
排序键首列 高频 + 高筛选率(日志场景通常是时间)
排序键列序 首列之后按基数升序
分区键基数 分区总数落在 100~1000
分区粒度 月或天,不出现小时/分钟级
过期数据删除方式 DROP PARTITION,不用全表 ALTER DELETE
跳数索引数量 每个都有"跳过量 >90%"的实测依据

六个高频坑:

  1. 以为主键唯一,拿它当唯一约束用,重复数据没人报警;
  2. 拿 ORDER BY 当"随便写写",首列放低基数字段,查询永远全扫;
  3. 分区键用 user_id,或切到分钟级,上线两周就开始报 Too many parts;
  4. 存储按容量买,一次买大,钱花在空盘上;
  5. 跳数索引建了一堆,写入慢了、查询没快;
  6. 高频小批量写入,part 合并追不上生产速度。

排序键和分区键定对了,慢查询、写入堆积、存储成本这三类问题会自动小一号。成本只是建表时多想十分钟。

相关文章
|
11天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
4160 22
|
11天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
4211 49
|
6天前
|
存储 弹性计算 人工智能
2026 年阿里云双十一活动入口攻略,新客服务器优惠通道、三大会场入口梳理
综合来看,2026年阿里云双十一活动入口清晰: 阿里云轻量应用服务器、阿里云ECS云服务器、阿里云GPU云服务器、阿里云百炼大模型服务平台 活动会场、综合权益中心、99计划专场三大入口覆盖服务器、AI权益与续费特价;新用户通过控制台首页banner、权益中心、产品页三处路径进入专属专场,老用户通过控制台弹窗和费用中心权益中心进入老客专区,企业用户做企业实名后解锁专属满减与阶梯折扣。
821 0
|
12天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
2025 7
|
6天前
|
云安全 人工智能 安全
|
5天前
|
Linux 开发工具 iOS开发
2026最新codex下载安装保姆级使用教程(下载+安装+登录+使用,含所有历史版本)
本文详解OpenAI Codex国内快速上手指南:提供Win/macOS/Linux全平台免安装包、npm/Homebrew等多方式安装、账号/API Key双登录、简体中文切换,覆盖下载、安装、汉化、使用及高频避坑(如微软商店失败、npm超时等),10分钟即可跑通。
1167 3
|
12天前
|
安全 算法 定位技术
《高性价比人生指南》完整原版:普通人用最少的资源,过好这一生的底层逻辑~How To Live Better
📖《高性价比人生指南》是一份基于实证、拒绝焦虑的生存手册,倡导以“人生时薪”为视角,重新计算时间、金钱与精力的成本与收益。它不承诺逆袭,只教人算清账:省下的钱若耗掉时间便亏;买体验比买物品更值;睡眠是最高杠杆的健康投资;关系贵在情绪价值而非表面热络;学习重在改变行为而非自我安慰。核心理念:用低成本、高回报的微小行动,换取长期的选择权——不是成为谁,而是掌控自己人生的主动权。
2150 6
|
云安全 安全 网络安全
|
3天前
|
人工智能 安全 API
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(dsh)是DeepSeek AI于2026年开源的轻量级Agent运行框架,基于Cordis内核,践行“一切皆插件”理念。支持Web/桌面双端,开箱即用;内置多模型接入、丰富插件生态(超3.5万),适配编程、办公、创作等场景。(239字)
769 0

热门文章

最新文章