ClickHouse是一种 **OLAP (Online Analytical Processing, 在线分析处理)**数据库
ClickHouse (列式存储):数据按列存储,每一列的数据在磁盘上是连续存放的。当您需要计算某一列的总和、平均值或进行分组统计时(例如 SELECT SUM(sales) FROM orders),ClickHouse只需读取sales这一列的数据,而无需加载所有其他列,从而极大地减少了I/O操作,查询速度因此得到数量级的提升
核心在于数据量 和查询模式。当遇到核心信号:当您的MySQL开始"慢"得无法忍受
最直接的信号是,您发现某些查询,尤其是分析类的报表查询,让您的MySQL数据库不堪重负。
痛点描述:您有一个包含数亿条记录的大表,当您尝试执行类似 SELECT product_id, COUNT(*) FROM order_details WHERE order_date >= '2024-01-01' GROUP BY product_id 这样的查询时,MySQL可能需要几分钟甚至几小时才能返回结果。更糟糕的是,这种慢查询会消耗大量CPU和I/O资源,拖慢整个线上业务,影响到正常的增删改查(OLTP)操作。
ClickHouse的解决方案 :同样的数据量和查询,ClickHouse凭借其列式存储 和向量化执行引擎,几乎可以在亚秒或数秒内完成。它只读取product_id和order_date这两列,而不是像MySQL那样加载整行数据,从而实现了数量级的性能提升
1. 列式存储 + 压缩
ClickHouse 列式存储(每列连续存储):
cluster_name列: [cluster1, cluster1, cluster1, cluster2, ...] ← 压缩率高(重复值多)
database列: [order_db, order_db, user_db, order_db, ...]
query_time列: [2.3, 2.5, 2.1, 0.8, ...]
timestamp列: [1705308185, 1705308192, 1705308198, ...]
读取时:只读需要的列 → I/O 减少 10-100 倍
案例:
-- 只需要统计,不需要 sql_text
SELECT
COUNT(*),
AVG(query_time)
FROM slowlog_data
WHERE cluster_name = 'prod-cluster1';
MySQL: 需要读取 sql_text 列(每行可能 1KB)→ 浪费 I/O
ClickHouse: 只读 query_time 列(8 bytes)→ I/O 少 100 倍
由于同一列的数据类型相同,具有较高的重复性..."
数据类型相同:这种结构非常规整,为高效压缩创造了基础条件。
较高的重复性(或相似性):
"...因此可以实现非常高的压缩比。"
正是因为上述的"同质性"和"重复性",ClickHouse 可以针对每一列的特点选择最适合的压缩算法,从而达到极高的压缩比。
对于 City 和 Event 这种重复值很多的字符串列,可以使用类似字典编码(Dictionary encoding)的方式。例如,将 "北京" 编码成 1,"上海" 编码成 2,"广州" 编码成 3。原始的 "北京", "上海", "北京", "广州" 就变成了 1, 2, 1, 3。存储一堆小整数显然比存储一堆长字符串要节省空间得多。
对于 Timestamp 这种连续递增的数值列,可以使用增量编码(Delta encoding)。它不直接存储每个值,而是存储第一个值和后续值与前一个值的差量。例如 1667884800, 1667884805, 1667884810, 1667884815 可以被压缩为 1667884800, 5, 5, 5。这样一来,原本很大的数字就变成了一堆小数字,更容易被进一步压缩。
在此基础上,ClickHouse 还会结合通用的压缩算法(如 LZ4, ZSTD)进行二次压缩,效果更佳。
2.向量化执行引擎:
ClickHouse 利用 CPU 的 SIMD(单指令多数据)指令集来实现向量化执行,这种方式可以对数据块进行并行处理
我们不再处理单个数据,而是处理一个"数据块"或"向量"
query_times = [2.3, 2.5, 2.1, 0.8, ...] # 一次读取一批(1024个)
avg = simd_avg(query_times) # CPU 一次计算多个值# ClickHouse 向量化执行(SIMD指令)
3.物化视图
ClickHouse 的物化视图与其他数据库的物化视图有一个核心区别:它是由源表的 INSERT 操作触发的。
它的工作流程如下:
定义源表 (Source Table):这是存储最原始、最详细数据的表。例如,用户的每一次点击日志。
定义目标表 (Target Table) :这张表用于物理存储物化视图的聚合结果。通常我们会使用一种特殊的表引擎,如 AggregatingMergeTree,来高效地存储和合并预聚合的状态。
创建物化视图:创建物化视图时,你需要:
指定它要监视的源表。
提供一个 SELECT 查询,定义你想要的聚合逻辑。
将它指向你创建好的目标表。
触发与聚合:
当一批新的数据 INSERT 到源表时,这个动作会像一个"触发器"。
物化视图会立刻 对这一批新数据执行你定义好的 SELECT 聚合查询。
然后,它将计算出的聚合结果写入到目标表中。
关键点 :这个聚合过程是增量的。它只处理新来的数据,而不是扫描整个源表,因此效率极高,几乎是实时的。