CK表入门

5 阅读3分钟

下面给你一份 ClickHouse 表设计/使用的“生产最佳实践清单” (偏通用、落地的那种),按你建表和跑业务最容易踩坑的点来讲。


1) 选对表引擎:99% 用 MergeTree 家族

明细事实表(日志/订单/曝光)

  • MergeTree / ReplicatedMergeTree
  • 分布式集群上:本地表用 ReplicatedMergeTree,查询用 Distributed

聚合结果表(日报/分钟级看板)

  • SummingMergeTree:适合 sum/count 这类可加和指标
  • AggregatingMergeTree:适合 uniqExact/quantile/... 聚合状态(用 xxxState/xxxMerge
  • ReplacingMergeTree:去重/最新状态(带 version 更稳)

别用普通 View 当加速器;要加速就用 物化视图 + 聚合表


2) 分区(PARTITION BY):用于“管理数据”,不是为了加速查询

最佳实践:

  • 大多数场景:按日期分区
    PARTITION BY toYYYYMM(dt)toDate(dt)
  • 分区不要太细(别按小时/分钟分区,除非有强需求)
  • 分区数量建议:每个表几百以内更稳(长期运行)

查询加速主要靠 ORDER BY(排序键) ,不是分区。


3) 排序键(ORDER BY):决定性能的核心

设计原则

  • 最常用过滤条件放前面
  • 再放高基数字段(如 user_id、ad_id)用于范围定位
  • 再放时间用于同 key 内的时序扫描

举例(广告曝光日志):

ORDER BY (dt, adx, campaign_id, user_id, ts)

常见坑

  • ORDER BY (ts) 单时间排序:范围查时间可以,但按业务维度过滤会很痛
  • 把低基数字段放太后:过滤会扫很多 granule

4) 主键/索引:理解 CK 的“稀疏索引”模型

  • CK 的 primary key 本质是 基于 ORDER BY 的稀疏索引
  • 不是 MySQL 那种逐行 B+Tree
    所以:排序键必须贴合查询模式

另外:

  • index_granularity 默认一般够用,别乱改
  • 真要加速特定过滤:用数据跳过索引(skip index),比如 bloom_filter / set / minmax(谨慎、先压测)

5) 数据类型:越“贴近真实”越快越省

推荐

  • 计数/金额:UInt32/UInt64、金额有小数用 Decimal(18, x)
  • 枚举/小范围:LowCardinality(String)(对低基数维度很香)
  • 时间:DateTime64(3)(毫秒)
  • 可空:尽量少用 Nullable(会慢,会占空间)

反例

  • 所有字段都 String
  • 随处 Nullable(String)
  • Float 存钱

6) TTL & 数据生命周期:强烈建议上

例如保留 30 天明细,自动删:

TTL dt + INTERVAL 30 DAY DELETE

冷热分层(有多卷/多磁盘时):

TTL dt + INTERVAL 7 DAY TO VOLUME 'cold'

7) 写入(INSERT)最佳实践:批量、顺序、避免小文件

  • ✅ 批量写:单批至少几千~几万行(看行大小)
  • ✅ 尽量按排序键大致有序写(能减少 merge 压力)
  • ❌ 避免超高频小批次写(会把 merges 打爆)

日志场景常见组合:Kafka -> Materialized View -> MergeTree


8) 分布式表:本地表存数据,Distributed 只负责查询路由

推荐结构:

  • xxx_local(ReplicatedMergeTree)存数据
  • xxx(Distributed)对外查询
  • MV 建在 xxx_local 上,不要建在 Distributed

9) 聚合表 + 物化视图:报表/看板的最优解

  • 明细表负责吞吐
  • MV 在写入时做聚合
  • 聚合表负责低延迟查询

这是 CK 在生产里最“值回票价”的用法。


10) 生产上最常见的 5 个坑

  1. ORDER BY 不贴合查询,导致扫全表
  2. 分区太细,parts 爆炸,merge 压力巨大
  3. 小批次写入过多,导致后台合并常年 100%
  4. 所有字段 String/Nullable,存储大、CPU 重
  5. 在 MV 里 JOIN 维表 / 基于 Distributed 建 MV(分布式下更容易炸)