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 聚合查询。
然后,它将计算出的聚合结果写入到目标表中。
关键点 :这个聚合过程是增量的。它只处理新来的数据,而不是扫描整个源表,因此效率极高,几乎是实时的。