把一条 85 秒的 ClickHouse 查询压到 400ms:四个月里一批朴素的增量优化如何叠加出 200 倍
来源: jordivillar.com — 2026-09-08
概述
Jordi Villar 记录了四个月里把一条「最贵」ClickHouse 查询从 85.7 秒压到约 400ms 的过程——没有任何奇技淫巧,全是朴素改动彼此叠加出超过 200 倍的提升。场景是要读 ReplacingMergeTree 全量历史、重用它并不擅长的 FINAL。他做的改动包括:把分区键从按月的 toYYYYMM 改成 `client_customer_id % 36`,换来 FINAL 的并行度并砍掉区间交叠计算;把 event_type 在排序键里的位置提前,少读约 7% 的行;把昂贵的 join 换成应用层预计算列,内存降近 13 倍;把 9 列换成 8 字节单列,再省下索引与 seeks;用扁平查询模板取代三层嵌套参数化视图,光解析与规划开销就从几百毫秒砍到近零(配 memcached 缓存编译产物)。最后靠调大 merge 上限并强制 24 小时以上旧 part 被合并,把 534 个 part 减到 378、表从 2.12TiB 瘦到 1.55TiB;再把「已结束周期」列加进 ORDER BY 第四位做 granule 过滤,单客户端从约千万行砍到不足十万行。
核心要点
- 把按月分区改成取模 36,换取 FINAL 并行度并省去区间交叠的构建开销
- 把 event_type 在排序键里提前位置(非 ALTER,需重建表)少读约 7% 行
- 把昂贵 join 换成应用层预计算列,查询内存降近 13 倍
- 用 dbt 把视图编译成扁平查询模板,砍掉解析/规划固定开销并配 memcached 缓存
- 把 merge 上限调高并强制合并超 24h 的旧 part,表从 2.12TiB 瘦到 1.55TiB
- 把已结束周期列推进 ORDER BY 第四位做 granule 过滤,行数降约 100 倍
金句
Changes were simple and incremental. None of them was a clever trick, just basic improvements compounding on each other.
👍 0
👎 0
返回 Lobsters 首页