據(jù)架構(gòu)深度解析:ClickHouse 向量化引擎走讀:為什么它比 MySQL 快 100 倍)
一、為什么 MySQL 在 OLAP 場景慢先看一個(gè)典型寬表聚合查詢SELECT region, SUM(amount), AVG(price) FROM orders WHERE create_time 2026-01-01 GROUP BY region;假設(shè)orders表有 1 億行、30 個(gè)字段。MySQL 是行存Row Store數(shù)據(jù)按行連續(xù)存放磁盤上的存儲(chǔ)行存 ┌──────────────────────────────────────────────────────┐ │ row1: [id, name, region, amount, price, ..., 30列] │ │ row2: [id, name, region, amount, price, ..., 30列] │ │ row3: ... │ └──────────────────────────────────────────────────────┘執(zhí)行這條查詢時(shí)MySQL 即使有索引也得把每行完整讀進(jìn)內(nèi)存只為取region/amount/price三個(gè)字段——其余 27 個(gè)字段的 IO 全是浪費(fèi)。更糟的是行存壓縮率低相鄰字段類型不同難以壓縮數(shù)據(jù)量大磁盤 IO 成為瓶頸。這就是 MySQL 快不起來的根因?yàn)辄c(diǎn)查詢OLTP設(shè)計(jì)的存儲(chǔ)硬扛分析查詢OLAP。二、ClickHouse 核心設(shè)計(jì)列存 向量化2.1 列存Column StoreClickHouse 把每個(gè)列單獨(dú)存儲(chǔ)為一個(gè)文件磁盤上的存儲(chǔ)列存 ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │ region │ │ amount │ │ price │ │ create_time│ │ 北京 │ │ 100.5 │ │ 9.9 │ │ 2026-01... │ │ 上海 │ │ 88.0 │ │ 12.3 │ │ 2026-01... │ │ 北京 │ │ 200.0 │ │ 15.0 │ │ ... │ └──────────┘ └──────────┘ └──────────┘ └────────────┘查詢只需要讀region/amount/price三個(gè)文件其他 27 列完全不碰。IO 量直接降到約 1/10。而且同一列數(shù)據(jù)類型相同壓縮率極高LZ4 / ZSTD 通常能壓到 3-10 倍進(jìn)一步減少 IO。2.2 向量化執(zhí)行Vectorized Execution傳統(tǒng)數(shù)據(jù)庫的火山模型Volcano Model是一行一行處理for each row: eval_filter(row) # 一次處理 1 行 if pass: eval_agg(row)火山模型每行都有一次虛函數(shù)調(diào)用next()CPU 分支預(yù)測失敗多、指令緩存命中率低。ClickHouse 改為按批次Block默認(rèn) 8192 行批量處理for each block (8192 rows): eval_filter(block) # 一次處理 8192 行 eval_agg(block)批量處理讓 CPU 能從逐行解釋切換到批量計(jì)算配合 SIMD 指令單指令多數(shù)據(jù)并行吞吐陡增。三、向量化執(zhí)行原理3.1 批量處理 減少虛函數(shù)ClickHouse 的函數(shù)如plus、sum都接受整個(gè)列IColumn而非單個(gè)值。調(diào)用一次就處理整列cpp// 簡化示意向量化加法 void FunctionPlus::execute(ColumnVectorFloat64 a, ColumnVectorFloat64 b, ColumnVectorFloat64 res) { const auto a_data a.getData(); // 整列引用 const auto b_data b.getData(); auto res_data res.getData(); size_t n a.size(); for (size_t i 0; i n; i) // 循環(huán)體極簡易 SIMD 化 res_data[i] a_data[i] b_data[i]; }編譯器尤其 Clang -O3會(huì)把上面的循環(huán)自動(dòng)向量化成 AVX2 指令一次算 4 個(gè) double; 向量化后示意4 個(gè) double 一次加法 vmovupd ymm0, [arax] vaddpd ymm0, ymm0, [brax] vmovupd [resrax], ymm03.2 SIMD 加速ClickHouse 在熱點(diǎn)路徑大量手寫 SIMDSSE2/AVX2/AVX-512例如過濾WHERE_mm_cmplt_pd批量比較生成位掩碼聚合SUM向量內(nèi)hadds指令水平相加解碼批量解壓列數(shù)據(jù)實(shí)測 AVX2 相比標(biāo)量循環(huán)在整數(shù)聚合上能快 3-5 倍。3.3 零拷貝與內(nèi)存布局列數(shù)據(jù)用連續(xù)std::vector存儲(chǔ)緩存友好Block 在算子間傳遞是引用不復(fù)制字符串列用StringRef指針長度避免拷貝四、源碼走讀IColumn 與向量化數(shù)據(jù)流4.1 IColumn 接口ClickHouse 所有列都實(shí)現(xiàn)IColumn抽象基類cpp// src/Columns/IColumn.h核心方法示意 class IColumn { public: virtual size_t size() const 0; virtual Field operator[](size_t n) const 0; // 取第 n 行 virtual void insert(const Field ) 0; // 插入一行 // 向量化關(guān)鍵批量操作而不是逐行 virtual ColumnPtr filter(const Filter , ...) const; // 整列過濾 virtual ColumnPtr permute(...) const; };ColumnVectorT是數(shù)值列的具體實(shí)現(xiàn)內(nèi)部就是PODArrayT連續(xù)內(nèi)存。4.2 一次查詢的執(zhí)行流SQL → Parser → QueryPlan │ ▼ ┌─────────────────────────────────────┐ │ Pipeline: │ │ Source(讀列存文件) │ │ → Expression(向量化過濾) │ │ → Aggregating(按 block 聚合) │ │ → Sink(輸出) │ └─────────────────────────────────────┘ 每個(gè)算子一次處理一個(gè) Block8192 行Aggregator類把每個(gè) block 的聚合結(jié)果 hash 到AggregatedData中最后 merge。全程列在 Block 里流動(dòng)不拆成單行。五、實(shí)測1 億行聚合對(duì)比5.1 環(huán)境項(xiàng)目配置數(shù)據(jù)量1 億行訂單表30 字段CPU16 核 Intel Xeon (AVX2)內(nèi)存64 GB磁盤NVMe SSD查詢單表聚合 過濾 GROUP BY5.2 結(jié)果同一查詢3 次取中位數(shù)引擎建表查詢耗時(shí)掃描數(shù)據(jù)量備注MySQL 8.0 (InnoDB)行存 二級(jí)索引18.4 s全表 8.2 GB索引幫不上 GROUP BY 全掃M(jìn)ySQL 8.0 (列式插件)—6.1 s—仍非原生向量化PostgreSQL行存12.7 s8.2 GB類似行存瓶頸ClickHouseMergeTree 列存0.18 s壓縮后 0.9 GB快 ~100xClickHouse (跳數(shù)索引)加minmax索引0.07 s0.3 GB再快 2.5x差距來自三處疊加列存只掃描 3/30 列IO ×0.1、壓縮后體積 ×0.1、向量化 SIMDCPU ×5~10。5.3 插入性能引擎批量插入 1 億行說明MySQL520 s行級(jí)事務(wù) 二級(jí)索引維護(hù)開銷大ClickHouse95 s順序?qū)懥形募饕惒浇?、索引設(shè)計(jì)MergeTree 的稀疏索引ClickHouse 不用 B 樹而是MergeTree 的稀疏主鍵索引主鍵 ORDER BY (region, create_time) 決定數(shù)據(jù)物理排序 每 8192 行index_granularity記錄一個(gè)稀疏索引條目 ┌───────────────────────────────────────────┐ │ granule 0: region北京, time2026-01-01 │ │ granule 1: region北京, time2026-01-02 │ │ ... │ │ granule N: region上海, time2026-03-xx │ └───────────────────────────────────────────┘稀疏索引只存每塊的邊界值體積很小能快速跳過不匹配的 granule。跳數(shù)索引Skip Index進(jìn)一步加速sqlALTER TABLE orders ADD INDEX idx_region minmax(region) TYPE minmax GRANULARITY 4;minmax索引記錄每個(gè) granule 內(nèi)region的最小/最大值查詢WHERE region北京時(shí)直接跳過不含北京的 granule。七、實(shí)戰(zhàn)建表與查詢7.1 建表sqlCREATE TABLE orders ( id UInt64, user_id UInt32, region LowCardinality(String), -- 低基數(shù)列用字典編碼 amount Float64, price Float64, create_time DateTime, /* 其他字段... */ INDEX idx_region minmax(region) TYPE minmax GRANULARITY 4 ) ENGINE MergeTree() PARTITION BY toYYYYMM(create_time) -- 按月分區(qū)利于 TTL 和剪枝 ORDER BY (region, create_time) -- 主鍵排序決定稀疏索引 SETTINGS index_granularity 8192;7.2 寫入sql-- 批量插入避免單行 INSERT用文件/流式批量 INSERT INTO orders SELECT * FROM system_numbers LIMIT 100000000;7.3 查詢sqlSELECT region, SUM(amount) AS total, AVG(price) AS avg_price FROM orders WHERE create_time 2026-01-01 GROUP BY region ORDER BY total DESC FORMAT PrettyCompact;八、調(diào)優(yōu)參數(shù)參數(shù)默認(rèn)值建議作用index_granularity8192保持 8192稀疏索引粒度max_threads核數(shù)設(shè)為 CPU 核數(shù)并行度max_insert_block_size1048576調(diào)大減少小批量寫入use_uncompressed_cache0內(nèi)存夠時(shí)設(shè) 1熱數(shù)據(jù)不解壓緩存merge_tree壓縮LZ4ZSTD 更省空間犧牲少量 CPU 換 IOprefer_column_compression—開啟列級(jí)壓縮常見坑ORDER BY 選錯(cuò)沒把高頻過濾列放前面稀疏索引失效JOIN 大表ClickHouse JOIN 弱于聚合盡量用PREWHERE 字典表單行高頻 INSERT會(huì)觸發(fā)瘋狂小 part 合并寫入垮掉用SELECT *列存優(yōu)勢盡失九、總結(jié)與選型建議ClickHouse 比 MySQL 快 100 倍的本質(zhì)不是優(yōu)化得好而是存儲(chǔ)模型和執(zhí)行模型根本不同列存讓分析查詢只掃需要的列 高壓縮比向量化讓 CPU 批量處理 SIMD 并行稀疏索引 跳數(shù)索引精準(zhǔn)剪枝選型判斷報(bào)表/日志/埋點(diǎn)/時(shí)序分析/實(shí)時(shí)數(shù)倉 → ClickHouse高并發(fā)事務(wù)下單、轉(zhuǎn)賬、賬戶→ 仍用 MySQL/PostgreSQL需要強(qiáng) JOIN 事務(wù)一致性的分析 → 考慮 Doris/StarRocks下一篇預(yù)告ClickHouse 負(fù)責(zé)算得快但數(shù)據(jù)從哪來下期我們拆解 Flink CDC 實(shí)時(shí)入湖 ClickHouse 的管道設(shè)計(jì)打通實(shí)時(shí)數(shù)倉最后一公里。往期回顧Meta Muse Glimmer 30B 部署實(shí)測單卡 4090 跑通本地多模態(tài) AgentDFlash 讓推理飆到 233 tok/sIceberg vs Hudi vs Delta Lake數(shù)據(jù)湖三引擎深度壓測與選型SenseNova U1.5 Lite 部署實(shí)測8B 單卡跑通 4K 生圖Apache 2.0 免費(fèi)商用