Cassandra 的分区键和聚簇键,几张图讲明白
先交代一下主角。Cassandra 是一个分布式 NoSQL 数据库,最早由 Facebook 开发,用来支撑收件箱这种海量写入的场景,现在是 Apache 顶级项目。它的卖点很直接:数据自动分片到几十上百台机器,写入吞吐量极高,任何一台挂了集群照样跑,加机器就能线性扩容。
你可以把它理解成一个"不怕数据多、不怕机器挂"的数据库。但"不怕"是有前提的——你的数据模型得建对。
Cassandra 查得慢,90% 的锅不在机器,在键。
分区键选错,数据全挤一个节点,热点炸了。聚簇键选错,范围查询变全表扫,毫秒变秒级。两个键加起来不到 20 个字符,决定了你整个数据模型的命运。
但很多人建表的时候,对着 PRIMARY KEY (a, b, c) 发呆:括号里第一个是分区键,后面的是聚簇键——我知道。可为什么要这么分?什么时候该把哪个字段放前面?
这篇文章用四张动图,把底层原理拆开给你看。看完你就知道怎么选了。
先搞清楚一个问题:Cassandra 为什么需要两种键?
传统数据库(MySQL、PostgreSQL)的数据存在一台机器上。查数据就像在图书馆里找书——索引告诉你书架号 + 第几层,一步到位。
Cassandra 不一样。数据分散在几十甚至几百台机器上。你面对的不是一个图书馆,而是一条街上几十家图书馆。
这就带来两个问题:
- 去哪家? —— 数据存在哪个节点上?
- 到了之后怎么找? —— 在那个节点内部,数据按什么顺序排?
分区键解决第一个问题。聚簇键解决第二个。
分区键:数据的「地址」

你写入一行数据,Cassandra 拿分区键的值做哈希,算出一个 token,然后把 token 放到一张哈希环上。环上按 token 范围划好了各节点的地盘。token 落在谁的地盘,数据就存谁那儿。
类比:分区键就像快递地址里的区号。同一个区号的所有包裹,都送到同一个分拣中心。
关键性质:同一个分区键的所有行,永远在同一个节点上。 这就是"分区"的含义。
所以选分区键的第一原则:让数据均匀分散。如果 80% 的请求都查 user_id=42,那 42 这个分区就成热点,对应节点 CPU 打满,其他节点闲着。
聚簇键:分区内部的「排序规则」

数据到了节点之后,同一个分区内可能有很多行。这些行按什么顺序存?答案是:按聚簇键排序,物理相邻存储。
类比:分拣中心收到一堆包裹后,按收件人姓名拼音排好放在架子上。你要找"张"开头的,直接从张那格开始拿,连续拿几格就行,不用翻遍整个架子。
这就是聚簇键的威力:范围查询只读连续的一段,不需要扫整个分区。
选聚簇键的原则:把你最常做范围查询的字段放前面。 比如时间线场景,created_at 做聚簇键,WHERE created_at > '2026-01-01' 就能秒回。
两键组合:一次定位 + 一段连续读

最好的查询长这样:
SELECT * FROM orders
WHERE user_id = 42
AND created_at BETWEEN '09:00' AND '10:05';
Cassandra 的执行路径:
- 分区键
user_id=42→ 哈希环 → 只去节点 B(A、C 完全不碰) - 节点 B 内,聚簇键
created_at范围 → 只读连续三行(其余不读)
一次网络跳转 + 一段磁盘顺序读。毫秒级。
这就是 Cassandra 设计的甜蜜点:查询条件和主键结构完美对齐。
反模式:没有分区键 = 挨家挨户敲门

如果你写了这么一条查询:
SELECT * FROM orders
WHERE created_at = '10:05';
注意:WHERE 里没有分区键。
Cassandra 懵了——没有地址,不知道该问谁。怎么办?只能广播:把查询发给集群里的每一个节点,每个节点都扫一遍自己的数据,再把结果交回协调节点合并。
这叫 scatter-gather。节点越多,越慢。10 个节点还行,100 个节点就是灾难。而且很容易超时。
分区键是 Cassandra 的地址。没地址,就只能挨家挨户敲门。
建模心法:三条实操建议
1. 分区键选高基数字段。
user_id、device_id、tenant_id 这种值很多、分布均匀的字段,天然适合做分区键。别用 status(只有几个值)或 country(分布不均)——会热点。
2. 聚簇键按查询模式排序。
你经常 ORDER BY created_at DESC?那 created_at 放聚簇键第一位。经常按 category 过滤?那 category 放前面。聚簇键的顺序 = 你支持的查询模式。
3. 一个分区别太大。
Cassandra 建议单分区不超过 100MB / 10 万行。如果你的分区键粒度太粗(比如用 year 做分区键,一年数据全挤一个分区),就会撑爆。解决办法:加一个"桶"字段,比如 year_month,把大分区拆小。
一张表总结
| 分区键 (Partition Key) | 聚簇键 (Clustering Key) | |
|---|---|---|
| 解决什么 | 数据去哪个节点 | 节点内怎么排序 |
| 类比 | 快递地址的区号 | 分拣中心里的排列规则 |
| 选错了会怎样 | 热点 / 数据倾斜 | 范围查询变全扫 |
| 查询时必须带? | 必须(否则全集群扫) | 建议带(不带也能查,但可能慢) |
写在最后
Cassandra 不是万能的。它的查询模型很"死"——你建表的时候就得想好怎么查,之后很难改。这跟 MySQL 那种"先存了再说,索引后面加"的思路完全相反。
但一旦你把键选对了,Cassandra 在大规模写入 + 按主键查询的场景下,性能是碾压级的。线性扩展、无单点、写入不阻塞读——这些优势的前提,就是你的数据模型和查询模式对齐。
分区键和聚簇键,就是那个对齐的锚点。
如果觉得有用,点个在看,转发给你身边被 Cassandra 慢查询折磨过的朋友。
有什么想法,欢迎在评论区聊聊——每一个留言我都会看。