ClickHouse完整指南

ClickHouse 引擎体系、建表索引与增删改查完整指南

ClickHouse 的核心能力由表引擎决定,不同引擎决定了数据的存储方式、合并规则、查询性能与支持的功能。本文系统梳理全量引擎分类、核心特点,以及生产最常用的建表、索引、增删改查语法与避坑规范。

一、引擎分类与核心特点

ClickHouse 引擎可分为 MergeTree 家族、分布式引擎、外部集成引擎、轻量存储引擎、特殊功能引擎、数据库引擎 六大类,其中 MergeTree 系列是生产环境的绝对核心。

1.1 MergeTree 家族引擎(生产核心)

底层支持主键稀疏索引、分区、TTL、后台数据合并、副本同步与分片扩展,适合海量明细数据与数仓场景,是绝大多数业务表的首选。

1.1.1 MergeTree(基础标准版)
  • 核心特点 :支持分区、主键索引、排序键,后台自动合并数据片段(Part);支持数据压缩、TTL 生命周期管理与字段增删改;主键仅用于索引,不保证唯一性,重复数据会全部保留
  • 适用场景:日志、埋点、订单流水等需要完整留存原始明细数据的场景。
1.1.2 ReplacingMergeTree(主键去重)

在 MergeTree 基础上增加主键去重能力,后台合并分区时,相同排序键的数据仅保留一条。

  • 可指定版本字段(如 update_time),合并时保留版本值最大的行;未指定则保留最后写入的行。
  • 仅后台合并时去重,未合并的分片查询时仍会返回重复数据,强一致场景需配合 FINAL 关键字。
  • 适用场景:用户维度表、商品维度表等需要按主键覆盖更新的维表。
1.1.3 SummingMergeTree(按主键聚合求和)

合并时对指定的数值列自动累加求和,非求和列保留同主键的第一条数据。

  • 适用场景:日活、交易额、指标汇总等预聚合统计场景,减少查询时的计算压力。
1.1.4 AggregatingMergeTree(通用预聚合)

支持 sum/count/min/max/uniq 等任意聚合函数,合并时持续对聚合状态做增量计算,是功能最强的预聚合引擎。

  • 字段需使用 AggregateFunction(函数, 类型) 定义,写入与查询需配合 -State/-Merge 函数。
  • 适用场景:多维报表、宽表预计算、高频聚合查询场景。
1.1.5 CollapsingMergeTree(标记折叠删除)

通过 sign 标记位(1 代表新增,-1 代表删除),合并时正负行互相抵消,实现软删除与数据撤销。

  • 适用场景:订单取消、退款、数据订正等存在删除/撤销的数据流场景。
1.1.6 VersionedCollapsingMergeTree(带版本折叠)

在 CollapsingMergeTree 基础上增加版本号,解决高并发乱序写入时折叠错乱的问题,适合实时乱序数据流。

1.1.7 GraphiteMergeTree(监控指标专用)

专门针对 Graphite 监控指标数据做自动聚合与压缩,运维监控场景专用。

补充:以上所有 MergeTree 子引擎均有对应的 Replicated* 副本版本(如 ReplicatedMergeTree),基于 ZooKeeper 实现多副本数据同步,生产集群高可用场景必须使用副本引擎。

1.2 Distributed 分布式引擎

本质是逻辑代理表,不存储真实数据,仅负责 SQL 路由与结果汇总:

  1. 写入时按分片规则(轮询/哈希/随机)将数据分发到集群各分片的本地表
  2. 查询时自动下发 SQL 到所有分片,汇总结果后返回
  3. 必须搭配底层真实存储的本地表(通常为 MergeTree 系列)使用
  • 适用场景:集群水平扩容、分布式存储与查询,是 ClickHouse 集群的标准用法。

1.3 外部集成引擎

用于对接第三方数据源,实现联邦查询与流式数据接入,多数不落地存储数据。

  • MySQL / PostgreSQL:直接映射关系库表,实时查询外部数据,支持跨库关联
  • Kafka:消费 Kafka 主题消息,配合物化视图可实现流式数据实时落库
  • Redis:读取 KV 数据,常用于维度关联查询
  • HDFS / S3 / File:直接读取 Parquet/CSV/ORC 等格式文件,无需导入即可查询,适配湖仓一体架构

1.4 轻量存储引擎(小数据/测试场景)

功能简单、资源占用低,适合临时表、测试数据与小体量场景。

  • TinyLog:单文件存储,无索引、无合并、不支持分区,仅适合少量测试数据
  • Log:比 TinyLog 增加标记文件,仍无索引,适合小批量低频查询临时表
  • Memory:数据全放内存,重启丢失,查询速度极快,适合临时中间结果、小维度字典表
  • Set :专门存储集合数据,用于优化 IN (xxx) 子查询性能
  • Dictionary:字典表引擎,将维表加载到内存,加速明细表维度关联

1.5 特殊功能引擎

  • Buffer:前端写入缓冲表,数据先写内存,异步批量刷入后端目标表,用于削峰填谷、抗高并发瞬时写入
  • View / MaterializedView:普通视图为虚拟表不存数据;物化视图写入原表时自动同步计算结果到目标表,实现实时 ETL 与数据分流
  • Merge:将多张同结构物理表逻辑合并查询,不拷贝数据,适合分月分表归档统一查询

1.6 数据库引擎

创建数据库时指定,决定库内表的管理方式:

  1. Ordinary:默认库引擎,可自由创建任意表引擎
  2. Atomic:推荐生产使用,支持原子 DDL、表原子替换、DROP 回收站,稳定性更强
  3. Lazy:库内冷数据表自动落盘,优化内存占用

二、建表语法与核心配置

以下围绕生产最常用的 MergeTree 系列展开,覆盖标准结构、核心参数与分布式建表规范。

2.1 标准建表完整结构

sql 复制代码
CREATE TABLE IF NOT EXISTS user_log
(
    `user_id`    UInt64      COMMENT '用户ID',
    `event_time` DateTime    COMMENT '事件发生时间',
    `event_type` String      COMMENT '事件类型',
    `page_url`   String      COMMENT '访问页面',
    `stay_time`  UInt32      COMMENT '停留时长(秒)',
    -- 建表时直接声明跳数索引
    INDEX idx_event_type event_type TYPE set(100) GRANULARITY 4
)
ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(event_time)       -- 分区键:按天分区
PRIMARY KEY (user_id, event_time)         -- 主键:生成稀疏索引
ORDER BY (user_id, event_time, event_type)-- 排序键:决定数据物理排序
TTL event_time + INTERVAL 30 DAY          -- TTL:30天后自动删除
SETTINGS index_granularity = 8192;        -- 索引粒度:每8192行一个索引标记

2.2 核心参数说明

参数 核心作用 注意事项
ENGINE 指定表引擎,决定存储、合并、去重逻辑 生产90%场景选用 MergeTree 家族
PARTITION BY 按分区键拆分数据目录,实现分区级管理 必须是高频查询过滤条件,通常为时间字段
ORDER BY 决定分区内数据物理排序,是稀疏索引的基础 查询过滤需满足最左前缀才能命中索引
PRIMARY KEY 稀疏索引的键,默认与 ORDER BY 一致 必须是 ORDER BY 的前缀,不可长于排序键
TTL 数据自动过期/冷热分层规则 可配置自动删除、移动到冷存储等策略
index_granularity 每N行记录一个索引标记 默认8192,越小索引越密,内存占用越高

2.3 常用 MergeTree 变体建表示例

ReplacingMergeTree(主键去重)
sql 复制代码
ENGINE = ReplacingMergeTree(update_time)  -- update_time为版本字段,合并保留版本最大行
ORDER BY user_id
SummingMergeTree(按主键聚合求和)
sql 复制代码
ENGINE = SummingMergeTree((stay_time, pv))  -- 指定需要累加的列
ORDER BY (user_id, event_date)

2.4 分布式表建表规范

分布式表本身不存数据,必须基于本地表创建,集群环境下需在所有节点执行:

sql 复制代码
-- 1. 创建本地表(每个分片节点存储真实数据)
CREATE TABLE user_log_local ON CLUSTER default_cluster
(
    `user_id` UInt64,
    `event_time` DateTime,
    ...
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/user_log_local', '{replica}')
PARTITION BY toYYYYMMDD(event_time)
ORDER BY (user_id, event_time);

-- 2. 创建分布式表(逻辑入口,所有节点均可读写)
CREATE TABLE user_log ON CLUSTER default_cluster
AS user_log_local
ENGINE = Distributed(default_cluster, db_name, user_log_local, rand());

三、索引机制与操作语法

ClickHouse 没有传统 B+ 树二级索引,分为**主键稀疏索引(默认自带)跳数索引(手动创建)**两类。

3.1 主键稀疏索引

  • 建表时通过 ORDER BY / PRIMARY KEY 自动创建,无需手动声明
  • 原理:每 index_granularity 行记录一个起始值到索引文件,查询时通过二分查找快速定位数据块
  • 限制:必须满足最左前缀匹配,例如排序键为 (a,b,c),仅查询 b 无法命中索引

3.2 跳数索引(Data Skipping Index)

用于加速非排序键列的过滤查询,通过预存每个数据块的统计信息,查询时直接跳过不满足条件的数据块。

创建方式
sql 复制代码
-- 建表后追加索引
ALTER TABLE user_log ADD INDEX idx_stay_time stay_time TYPE minmax GRANULARITY 4;

-- 建表时内联定义(见2.1标准建表示例)
常用索引类型
类型 适用场景
minmax 数值/时间列,存储最大最小值,适合范围查询
set(max_size) 低基数枚举列,存储去重值集合,适合等值查询
bloom_filter 高基数字符串,布隆过滤器,适合等值判断
ngrambf_v1 字符串模糊查询(LIKE 场景)

3.3 索引管理语句

sql 复制代码
-- 查看表索引
SHOW INDEXES FROM user_log;

-- 删除索引
ALTER TABLE user_log DROP INDEX idx_event_type;

-- 物化索引:对历史存量数据生效
ALTER TABLE user_log MATERIALIZE INDEX idx_event_type;

四、增删改查(DML)语法

4.1 数据写入(INSERT)

ClickHouse 写入性能极强,但禁止逐条小批量写入,必须攒批提交。

sql 复制代码
-- 批量值插入(推荐单批次1000~10万行)
INSERT INTO user_log (user_id, event_time, event_type)
VALUES
(1001, '2024-07-17 10:00:00', 'view'),
(1002, '2024-07-17 10:01:00', 'click');

-- 查询结果插入(ETL场景最常用)
INSERT INTO user_log SELECT * FROM user_log_staging WHERE dt = '20240717';

-- 指定格式导入(CSV/JSON等)
INSERT INTO user_log FORMAT CSV ...;

4.2 数据查询(SELECT)

兼容绝大多数标准 SQL 语法,支持 JOIN、子查询、窗口函数等。

sql 复制代码
-- 基础聚合查询
SELECT user_id, count(*) AS pv
FROM user_log
WHERE event_time >= '2024-07-17'
  AND event_type = 'view'
GROUP BY user_id;

-- FINAL 关键字:强制合并去重(仅 Replacing/Collapsing 等引擎有效)
SELECT * FROM user_log FINAL WHERE user_id = 1001;

4.3 数据更新(ALTER UPDATE)

ClickHouse 无行级实时更新,更新通过 Mutation 异步合并实现,属于重量级操作。

sql 复制代码
-- 语法:按条件更新指定列
ALTER TABLE user_log UPDATE stay_time = 120 WHERE user_id = 1001 AND event_time = '2024-07-17 10:00:00';

4.4 数据删除

按条件删除(异步 Mutation)
sql 复制代码
ALTER TABLE user_log DELETE WHERE user_id = 1001;
按分区删除(推荐,性能极高)

直接删除整个分区目录,几乎无开销,是生产首选删除方式:

sql 复制代码
ALTER TABLE user_log DROP PARTITION '20240717';
清空全表
sql 复制代码
TRUNCATE TABLE user_log;

4.5 Mutation 异步任务查询

更新/删除提交后后台异步执行,可通过系统表查看执行进度:

sql 复制代码
SELECT
    command,
    is_done,
    progress,
    fail_reason
FROM system.mutations
WHERE table = 'user_log'
ORDER BY create_time DESC;

五、生产核心注意事项与选型指南

5.1 关键避坑要点

  1. 主键不等于唯一约束:MergeTree 主键仅用于索引,不保证数据唯一;ReplacingMergeTree 仅合并时去重,未合并前仍有重复,强一致场景需谨慎。
  2. 更新删除是重量级异步操作:Mutation 会重写整个数据分区,禁止高频小批量更新删除,否则会导致 Part 数量爆炸,严重影响查询性能。
  3. 排序键决定查询性能上限:必须按高频过滤、分组维度设计排序键,遵循最左前缀原则;排序键不宜过长(建议不超过5列),避免索引膨胀。
  4. 查询必须带分区条件:不带分区键会扫描全部分区,大表极易超时;分区粒度推荐按天/按月,避免过细(按小时)或过粗(按年)。
  5. 写入必须攒批 :单次 INSERT 会生成新的 Part,逐条高频写入会触发 Too many parts 报错;生产建议单批次 5000~50000 行,每秒 1~2 批次。
  6. 慎用 FINAL 关键字FINAL 会触发实时合并,大表查询性能下降显著;优先通过业务设计避免重复,不要默认全量查询加 FINAL。
  7. 不支持事务与行级锁:无事务机制,写入失败不回滚;无行级锁,并发更新后提交的会覆盖,不适合强一致 OLTP 场景。

5.2 场景选型速查表

业务场景 推荐引擎
日志/明细原始数据留存 MergeTree
维表、需按主键更新去重 ReplacingMergeTree
指标累加、简单预聚合 SummingMergeTree
多维复杂聚合报表 AggregatingMergeTree
订单撤销、软删除数据流 CollapsingMergeTree
集群分片分布式存储 Distributed + 本地 ReplicatedMergeTree
实时消费 Kafka 数据 Kafka + 物化视图落 MergeTree
MySQL 跨库关联查询 MySQL 引擎
临时测试、小数据量表 TinyLog / Memory
相关推荐
TDengine (老段)1 小时前
TDengine JOIN 完整语法 — Inner/Outer/ASOF/Window 全语法详解
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
ai_coder_ai1 小时前
编写自动化脚本,在自己后端服务中使用云原生Baas服务进行编码和解码相关操作
数据库·云原生·自动化
hehelm2 小时前
AI 大模型接入 SDK —项目概述
linux·服务器·网络·数据库·c++
Database_Cool_2 小时前
阿里云 Lindorm vs Elasticsearch 检索存储一体对比:多模数据库一站式方案首选
数据库·阿里云
大郭鹏宇2 小时前
下篇:LangChain Agent 智能体从入门到实战(二)—— 记忆管理、中间件与最佳实践
网络·数据库·人工智能
facaixxx20243 小时前
雨云游戏服务器MCSM面板指南:低延迟BGP线路(一键开服)
运维·服务器·游戏
数行拙笔3 小时前
Redis---set类型
数据库·redis·缓存
Leon-Ning Liu3 小时前
【真实经验分享】Oradebug抓取阻塞源SQL语句
数据库
焦点链创研究所3 小时前
算力核心机器人将于 7 月 18 日发布
运维·服务器·机器人