ClickHouse¶
ck讲一下特点(clickhouse的优点)¶
- 极速查询
- 列式存储 + 向量化引擎,利用 SIMD 指令批量处理数据,适合海量数据聚合分析,轻松实现每秒亿级行处理。
- 高效压缩
- 列式数据高冗余性结合自适应压缩(LZ4/ZSTD),压缩比 5~10 倍,显著降低存储成本。
- 实时能力
- 支持高吞吐写入(百万行/秒)与写入后立即可查,无需预计算,适合实时监控、日志分析。
- 支持 SQL
- 完整支持 ANSI SQL,内置 800+ 函数,直接处理 JSON、数组等复杂结构,学习成本低。
- 分布式扩展
- 原生分片与副本机制,MPP 架构并行计算,轻松扩展至 PB 级数据,保障高可用。
- 灵活存储引擎
- 以 MergeTree 系列引擎为核心,支持分区、TTL、预聚合等特性,适配时序、日志等场景。
- 低运维
- 自动合并数据块、清理过期数据,单机无需外部依赖,分布式可选内置 ZooKeeper 替代
ClickHouse 的 列式存储 和 向量化执行引擎¶
ClickHouse 极致性能背后的关键因素是真正的列式存储和极致性能的向量化执行引擎
- 向量化是提升 OLAP 查询性能的一种常用技术。
- 向量化是指对不同的数据执行同样的一个或一批指令,或者说把指令应用于一个数组/向量,通过 CPU 数据并行,实现单指令、多数据(简称 SIMD)
- 在 ClickHouse 中,向量化的实现主要通过 SIMD 内置函数和编译器自动向量化。
- 大量使用 SIMD 内置函数对关键代码路径进行优化
- 通过良好的架构设计和代码设计,使得编译器能够生成良好的向量化代码。
- 向量化的局限:在严重依赖于控制流,即包含大量分支、跳转和条件判断语句的任务中,则难以实现向量化
- 列式存储
- 按列存储数据,查询特定的数据时,只有选中的列被加载和扫描,而不是整个表。这大大提高了查询性能
- 列式存储除了降低IO和存储的压力之外,还为向量化执行做好了铺垫。
clickhouse为什么用列式存储(列式存储有什么优势)¶
- 高效的数据压缩
- 列式存储中,同一列的数据类型相同,便于压缩。
- 高压缩率减少了存储空间和I/O开销,提升了查询性能。
- 减少I/O操作
- 查询时只读取相关列,避免读取无关数据。
- 降低了I/O负载,尤其在大数据场景下,性能提升显著。
- 向量化执行
- 列式存储便于使用SIMD指令进行批量处理。
- 提高了CPU利用率,加速了查询执行。
- 更好的缓存利用率
- 列式存储的数据更紧凑,适合CPU缓存。
- 减少了缓存未命中,提升了查询速度。
- 适应OLAP场景
- OLAP查询通常涉及大量数据的聚合和扫描。
- 列式存储特别适合这类操作,性能优于行式存储。
- 自动索引
- 因为基于列存储,所以每一列本身就相当于索引。
- 所以在做一些需要索引的操作时,就不需要额外的数据结构来为此列创建合适的索引。
clikhouse和doris有什么区别¶
ClickHouse 讲一下,在数仓中用来干嘛,你对ck的了解(讲优点)¶
- 极速查询
- 列式存储 + 向量化引擎,利用 SIMD 指令批量处理数据,适合海量数据聚合分析,轻松实现每秒亿级行处理。
- 高效压缩
- 列式数据高冗余性结合自适应压缩(LZ4/ZSTD),压缩比 5~10 倍,显著降低存储成本。
- 实时能力
- 支持高吞吐写入(百万行/秒)与写入后立即可查,无需预计算,适合实时监控、日志分析。
- 支持 SQL
- 完整支持 ANSI SQL,内置 800+ 函数,直接处理 JSON、数组等复杂结构,学习成本低。
- 分布式扩展
- 原生分片与副本机制,MPP 架构并行计算,轻松扩展至 PB 级数据,保障高可用。
- 灵活存储引擎
- 以 MergeTree 系列引擎为核心,支持分区、TTL、预聚合等特性,适配时序、日志等场景。
- 低运维
- 自动合并数据块、清理过期数据,单机无需外部依赖,分布式可选内置 ZooKeeper 替代
你说ck快,为什么快,原理是什么,有了解吗?¶
ClickHouse 采用列式存储,这意味着同一列的数据被存储在一起。这种存储方式在处理分析类查询时具有天然优势,因为只需要读取相关列的数据,从而大大减少了I/O操作 ClickHouse 可利用 SIMD 内置函数进一步加速执行效率(向量化执行)。这部分是 ClickHouse 优于大量同类 OLAP 产品的重要因素
你用过ck的什么引擎,用来干嘛,为什么用它,举例一个查询场景来讲一下¶
ReplacingMergeTree:在 MergeTree 的基础上,支持对相同主键的数据进行去重。
1. 基础定义¶
ClickHouse 是 Yandex 开源列式存储 OLAP 分析型数据库,面向海量日志、行为数据实时多维聚合分析;C++ 编写,无第三方依赖,单二进制部署,支持 PB 级数据秒级查询。 - OLAP:海量数据聚合、多维度统计、大批量写入 - 不适合:OLTP、高频单行 UPDATE/DELETE、强事务、高并发点查
2. 为什么 ClickHouse 速度极快(面试高频)¶
- 列式存储 查询仅加载需要的列,大幅减少 IO;同类型数据连续存放,压缩率 5~20 倍(LZ4/ZSTD/Gorilla)。
- 向量化执行 Vectorized Execution 内存以 Block(块,默认 8192 行)为单位批量计算,配合 CPU SIMD 单指令多数据,避免逐行循环、减少分支预测失效。
- LSM 架构 MergeTree 异步合并 写入轻量、无锁;后台异步合并小 parts,写入与查询互不阻塞,支持高吞吐实时写入。
- 多层数据裁剪(Pruning) 分区裁剪 → 主键稀疏索引裁剪 → 跳数索引裁剪,跳过大量无关数据,几乎不用扫描全量。
- 全链路并行 单机多核并行、分布式分片并行、查询算子内部并行。
- 即时编译 JIT 简单查询生成机器码,消除解释执行开销。
3. 行存 vs 列存对比(必考)¶
| 维度 | 行存储(MySQL/OLTP) | 列存储(ClickHouse/OLAP) |
|---|---|---|
| 存储方式 | 一整行连续存储 | 同一列所有值连续存储 |
| 适用场景 | 单点查询、频繁更新、多字段返回 | 聚合统计、宽表、只查少量列 |
| IO 开销 | 查询少量列也要读整行,IO 高 | 仅读取查询涉及列,IO 极低 |
| 压缩效率 | 差,字段类型混杂 | 极高,同类型连续,压缩比高 |
| 缓存友好 | 差,行分散 | 优秀,连续内存命中 CPU Cache |
| 写入性能 | 批量写入一般,单行快 | 批量写入极强,单行插入性能差 |
二、核心存储引擎(MergeTree 全家桶,面试重中之重)¶
1. MergeTree(基础核心引擎,生产标配)¶
底层基于 LSM-Tree,数据拆分为不可变 Part(数据片段),写入生成小 Part,后台自动合并;支持分区、稀疏主键索引、TTL、副本、压缩。
核心配置三要素:
1. ORDER BY:排序键(稀疏索引依据,等同于主键),基数从高到低排,例 (date, user_id)
2. PARTITION BY:分区键,粗粒度快速裁剪,一般按天/小时分区
3. PRIMARY KEY:稀疏索引,默认与 ORDER BY 相同,可缩短前缀
磁盘文件结构(Part 内部)¶
.bin:列原始压缩数据.mrk:标记文件,索引粒度index_granularity=8192,每 8192 行记录磁盘偏移.idx:主键稀疏索引(mark 对应主键值).minmax:分区/part 列极值,用于分区裁剪.txt:元数据(行数、分区值等)
稀疏索引原理(高频面试)¶
非每行索引,每 index_granularity 行存一条索引标记;查询时先过滤 mark 区间,只读取命中块,避免全表扫描。
设计规范:ORDER BY 第一列必须是高频过滤字段(日期最优)。
2. MergeTree 衍生引擎(业务场景必考)¶
- ReplicatedMergeTree 带副本高可用,依赖 ZK 同步 parts、元数据;生产集群必用,多副本容灾,最终一致性。
- ReplacingMergeTree(去重)
合并时根据版本字段
ver保留最新一条,解决重复写入(日志重放、重试);注意:只有合并时才去重,未合并小 part 仍会查出重复。 - SummingMergeTree(预聚合) 合并时自动求和数值列,提前聚合减少查询计算,适合指标看板、UV/PV 统计。
- CollapsingMergeTree(折叠) 用 sign=1(新增)/-1(删除) 正负行抵消,实现逻辑删除/变更,适用于用户画像、流水变更场景。
- VersionedCollapsingMergeTree:折叠+版本,解决乱序写入。
3. 辅助引擎(了解即可)¶
- Memory:内存表,重启丢失,缓存中间结果
- Buffer:写入缓冲,批量刷下游 MergeTree,削峰
- Distributed:分布式逻辑表,路由读写到本地分片
- File/MySQL/Kafka:外部表引擎,数据导入导出
三、索引体系(三层裁剪,优化核心)¶
- 分区索引 Partition Prune(第一层粗裁) PARTITION BY 字段,查询带分区条件直接跳过整个分区;最优分区粒度:单日分区,避免分区过多/过少。
- 主键稀疏索引 Primary Index(第二层) ORDER BY 构建,粒度 8192 行 mark,定位数据块。
- 跳数索引 Data Skipping Index(第三层精细过滤) 对非排序键建立,进一步过滤块,常用类型:
- minmax:列最大最小值(日期、数值)
- bloom_filter:字符串、ID 等值查询
- set:枚举值(事件类型、渠道)
- ngrambf_v1:模糊 like 查询
四、分布式架构(集群面试核心)¶
1. 分片 Shard + 副本 Replica¶
- Shard(分片):数据水平拆分,分担存储与计算;分布式表通过
shard_key哈希路由数据到对应分片。 - Replica(副本):每个分片多副本,ReplicatedMergeTree + ZK 同步,高可用。 架构分层:本地表(ReplicatedMergeTree)+ 分布式表(Distributed)对外提供统一入口。
2. Zookeeper 作用¶
- 副本间同步 Part 元数据、合并任务
- 选举副本主节点,写入协调
- 存储复制队列、mutation 任务、分区元数据
- 分布式 DDL 同步
3. 分布式写入流程¶
- 写入 Distributed 表,按 sharding key 哈希路由到对应分片副本;
- 分片本地写入生成 part,同步至 ZK;
- 其他副本拉取 part,后台合并;
- 多副本写入默认异步,可设置同步等待副本落盘。
4. 分布式查询流程¶
- 接收节点解析 SQL,下发到所有相关分片;
- 各分片本地并行查询、聚合中间结果;
- 接收节点汇总分片结果,最终聚合返回。
五、数据写入、更新、删除机制(高频踩坑题)¶
1. 写入特性¶
- 仅支持批量 INSERT 性能优秀,单行 INSERT 极慢;推荐 Flink/Spark 批量、Buffer 引擎缓冲。
- 写入生成小 Part,大量小 Part 会严重拖慢查询(文件 IO、索引遍历),后台 Merge 合并控制 part 数量。
- 不支持实时单行 update/delete,标准更新用 Mutations。
2. Mutations(ALTER UPDATE/DELETE)¶
- 异步后台任务,重写整个 Part,性能差,禁止高频执行;
- 适用低频修正数据,不适合业务实时变更;
- 执行记录在 ZK,消耗磁盘与 CPU,大量 mutation 导致集群卡顿。
3. 三种去重方案对比(面试常问)¶
- ReplacingMergeTree:简单重复,靠版本合并去重;查询可能出现重复,需手动 FINAL。
- 写入层幂等:上游生成唯一主键,Flink 分区去重,最优推荐。
- Mutations DELETE:性能差,仅少量脏数据修复使用。
4. TTL 冷热数据清理¶
支持列级别、行级别 TTL,后台自动过期删除旧数据,适合海量日志自动归档清理。
六、性能优化全套(项目经验必说)¶
1. 表结构设计优化¶
- 分区:按天 PARTITION BY toDate(event_time),避免小时分区过多。
- ORDER BY 排序键设计:高频过滤字段放前面,基数递减
(date, hour, user_id)。 - 字段类型优化:
- 时间:DateTime / UInt64 时间戳,少用 String 存时间;
- ID:UInt32/UInt64 代替 String;
- 金额:Decimal 避免浮点精度丢失;
- 少用 Nullable:增加存储开销、破坏索引连续性;
- 定长 FixedString 存 traceId、UUID,速度更快。
- 合理添加跳数索引,高频过滤非排序键建 bloom_filter。
- 宽表设计,多维度冗余,减少多表 JOIN(ClickHouse JOIN 性能弱)。
2. 写入优化¶
- 批量插入,单次万级行;禁用单行循环插入。
- Buffer 引擎缓冲写入,合并小批量刷入 MergeTree,减少 part 数量。
- Flink 写入:batchSize、flush 时间合理配置,均衡延迟与 part 数量。
- 分片 sharding key 均匀分布,避免数据倾斜。
- 控制后台合并线程、合并阈值,防止写入高峰合并抢占 IO。
3. 查询优化¶
- 强制分区裁剪:WHERE 必须携带分区字段,禁止全分区扫描。
- 只 SELECT 需要的列,杜绝
SELECT *。 - 利用稀疏索引:过滤条件包含 ORDER BY 前缀字段。
- 预聚合:SummingMergeTree / 物化视图 Materialized View 提前计算指标。
- 避免大 JOIN,大表关联性能差;采用宽表冗余替代。
- 分布式查询开启
distributed_group_by_no_merge下推聚合到分片,减少网络传输。 - 物化视图预计算 UV、PV、日活等固定指标。
4. 集群运维优化¶
- ZK 独立部署,内存充足,避免 ZK 瓶颈。
- 磁盘使用 SSD,Part 合并大量随机读。
- 控制单表 Part 总数,过多小文件会导致元数据加载缓慢。
- 冷热数据分离,TTL 自动清理历史数据。
- 分片数据均衡,避免单分片数据倾斜。
七、高频面试题(分基础、原理、项目踩坑,附带标准答案)¶
基础概念题¶
-
ClickHouse 适用与不适用场景? 适用:用户行为日志、埋点分析、实时指标看板、监控时序数据、海量离线多维报表; 不适用:订单交易事务、高频单行更新、在线业务点查、强一致性多表事务。
-
列式存储优势,为什么 OLAP 必须列存? ① 只读取查询列,IO 大幅降低;② 同类型连续存储,压缩率极高;③ 连续内存匹配 CPU 缓存 + SIMD 批量计算,聚合速度远超行存。
-
MergeTree Part 过多会有什么问题?怎么解决? 问题:查询时遍历所有 part 索引,大量文件 IO,查询超时、CPU 打满; 解决:批量写入、Buffer 缓冲、调大后台合并参数、合理分区、定期 optimize 手动合并。
-
ReplacingMergeTree 一定会自动去重吗? 不会。只有后台合并多个 part 时才会按版本去重;未合并的多个小 part 仍会查出重复,查询需加
FINAL强制合并视图去重,FINAL 性能损耗大,不建议线上频繁使用。
底层原理深度题¶
-
稀疏索引与 B+ 树索引区别? B+树每行一条索引,适合点查;ClickHouse 稀疏索引每 8192 行一条,索引体积极小,适合大范围扫描聚合,不适合单行精准查询。
-
Mutations 底层原理与缺点? ALTER UPDATE/DELETE 属于 Mutations,异步任务;后台重写整个受影响 part,生成新 part,旧 part 标记待删除; 缺点:IO、CPU 开销巨大,大量 mutation 阻塞合并与查询,只适合低频数据修正。
-
分布式表 Distributed 写入数据倾斜如何解决? ① 更换均匀哈希 sharding key(userid、traceid),避免基数极小字段;② 数据倾斜分片单独扩容;③ 上游打散数据再写入。
-
Zookeeper 在 ClickHouse 集群的作用?单机版是否需要 ZK? 单机普通 MergeTree 不需要;ReplicatedMergeTree 副本集群必须 ZK:同步 part、副本选举、mutation 队列、分布式 DDL、复制任务协调。
-
ClickHouse 事务支持?ACID? 仅支持快照隔离,无完整 ACID;
- 写入单 Part 原子;
- Mutations、跨分片无事务;
- 副本依靠 ZK 保证副本同步最终一致性,不支持强事务。
调优 & 项目实战面经(面试官最爱深挖)¶
-
线上查询慢,排查步骤? ① 查看 SQL 是否带分区条件,无分区裁剪是首要问题; ② 查看 SELECT 是否查大量无用列,存在
SELECT *; ③ 检查 ORDER BY 排序键是否匹配 WHERE 过滤条件,无法走稀疏索引; ④ 查看单表 part 数量,大量小文件拖慢扫描; ⑤ 分布式场景是否聚合未下推,大量数据网络传输; ⑥ 硬件瓶颈:磁盘 IO、CPU、ZK 压力。 -
Flink + ClickHouse 实时埋点架构,踩过什么坑? 坑1:单行写入,生成海量小 Part,查询超时; 解决:Flink 设置批量刷写,搭配 Buffer 引擎缓冲。 坑2:数据重复写入,出现重复 UV; 解决:Flink 端基于 traceId 分区去重,或 ReplacingMergeTree + 业务版本号。 坑3:分片数据倾斜,单节点负载过高; 解决:选用均匀 sharding key,拆分热点用户。 坑4:小时分区过多,元数据膨胀; 解决:统一按天分区,通过 where 过滤小时。
-
ClickHouse JOIN 性能差,怎么优化多表关联? ① 宽表建模,提前冗余维度字段,消除 JOIN; ② 小维度表使用 Dictionary(字典表)内存加载关联; ③ 大表关联拆分计算,先分片本地聚合再汇总; ④ 分布式场景使用 local join 减少跨分片数据传输。
-
什么是物化视图 Materialized View,作用? 预聚合视图,写入主表时同步计算并写入视图;用于提前计算 UV、PV、各类汇总指标,查询直接读取预聚合结果,大幅降低实时查询耗时。底层本质是触发器 + 另一张 MergeTree 表。
压力/场景追问¶
- 千万/亿级日志,日增 TB 级,ClickHouse 如何承载?
- 集群分片水平扩容,数据分片拆分;
- 按天分区,分区裁剪过滤海量历史数据;
- Buffer 批量写入,控制 part 数量;
- TTL 自动清理超期冷数据,控制存储总量;
- 物化视图预聚合指标,线上报表不走原始明细;
-
多副本保障高可用,SSD 提升合并与查询 IO。
-
如何实现 ClickHouse 高可用?
- 每个分片部署多副本 ReplicatedMergeTree;
- ZK 集群三节点以上容灾;
- 分布式表统一入口,自动路由健康副本;
- 磁盘 RAID、定时备份分区数据;
- 监控 part 同步、副本延迟、ZK 连接状态。
八、常见踩坑总结(面试加分项)¶
- 大量小 Part:批量写入、调合并参数、定期 Optimize;
- 全分区扫描:SQL 必带分区字段;
- 滥用 FINAL:只离线修复数据使用,线上查询禁用;
- 频繁 Mutation:业务侧规避更新,上游幂等写入;
- Nullable 泛滥:字段尽量非空,降低存储与索引开销;
- Sharding Key 倾斜:选择高基数均匀 ID;
- ZK 压力过大:拆分 ZK、减少副本同步任务、控制 mutation 频率;
- 小时级细分区:分区过多元数据爆炸,统一天分区。