让一条看板查询,少扫 230 倍的数据
一个你能自己跑的 ClickHouse 调优 demo:同一张 5000 万行的事件表,朴素 schema 对比调优后的 schema,用数据库自己的 query_log 度量。一条带过滤的看板查询,从扫描 1.9 GiB 降到约 8 MiB——大约少扫 230 倍数据、快 16 倍——一个日聚合再用 projection 提速 54 倍。一条命令从空库重建;CI 每次推送都重跑,一旦调优退化就让构建失败。
问题
一张分析表涨到几千万、上亿行,架在它上面的看板就慢成蜗牛。每条查询读的数据远超所需,延迟往上爬,而在按量计费的仓库上,账单也跟着爬。惯常反应是"加机器"——那是花钱把同样浪费的字节扫得更快,而不是少扫一些。
约束:用数字证明,不靠感觉
调优建议好说难信。所以整件事都为"可度量、可复现"而建:两个 schema 上用完全相同的数据和查询,提升直接从 query_log 读出(读取字节数、读取行数、耗时),再用一条命令从空库重建整个基准,让任何人都能自己核对结果。
是什么在推动这些数字
-
与查询方式匹配的排序键——对的
ORDER BY加分区,让 ClickHouse 整段跳过数据、而非读取它们,这正是"少扫 230 倍字节"的来源。 - 为重聚合用 projection——projection 预计算一个日聚合,让那份周期性报表读一个很小的物化结果,而不是重扫基表,换来 54 倍提速。
-
合适大小的类型——
LowCardinality和更紧的列类型,从源头缩小了需要读取和驻留内存的量。 - 回归闸门——基准在 CI 里每次推送都跑,一旦某次 schema 改动悄悄让查询又多扫了,就让构建失败,于是"赢"能一直是"赢"。
为什么这正是我擅长的问题
数据平台的可靠性是我的中心:六年后端里,大部分是在负载下构建和运维 ETL 与存储——一次 7 微服务跨库迁移、把吞吐从 50 拉到 5000 QPS、一次 binlog 级恢复零停机找回 100% 丢失数据。这里的直觉一样:不争论性能,给它上仪表、用数据库自己的数字证明提升,再套一道闸门让它不会悄悄烂掉。
证明
可运行、可复现、还有视频。完整基准公开在 GitHub 上——朴素与调优两套 schema、查询、以及 query_log 数字——一条命令从空库重建,GitHub Actions 每次推送都重跑。另有一段 3 分钟的实时运行走查。数据集是生成的 5000 万行基准,而非某个具体客户的数据;它证明的是方法与实测结果,可直接迁到真实仓库上。 代码 → · 3 分钟走查 →
还能用在哪
任何"查询扫得比应该扫的多"的分析/OLAP 场景:产品分析、事件管线、报表仓库、随数据变大而变慢的看板。如果一条查询感觉慢、却没人说得清到底为什么,第一步是量它真正读了多少——然后让它读得远远更少。
什么情况下这招不适用
- 如果慢在网络、并发排队或客户端反序列化,重排物理布局帮不上忙。先量:read_bytes 正常,就不是这个问题。
- 如果每条查询的过滤条件都不一样(真正的临时分析),一种排列没法同时伺候所有查询,收益会大幅缩水。
- 如果你的瓶颈在写入而不在查询,那是另一个问题,用的是另一套工具。
要转述的话,就这一句
"他用数据库自己的日志量出扫描量降到 1/230,然后写了个 CI 门控,让它回不去。"
如果你造的机器需要一套界面、一个设备连接,或者数据必须落到别处去——告诉我它现在正让你付出什么代价。你会得到一个诚实的判断:能不能解;通常还会收到一个能跑的东西。从这里开始 →