bigywater.tech
ClickHouse 内部原理 · 3

ClickHouse 一条查询是怎么执行的

同一条 SELECT,用 EXPLAIN AST / PLAN / PIPELINE 加 query_log 拆开看它从文本到结果,经过了哪几层。

4层
AST→Plan→Pipeline→执行
3个
1个Sorting计划节点展开出的处理器数
4ms
执行耗时(query_log记录)

做的事:给同一条 SQL 拍四张 X 光片

对同一条查询,用 ClickHouse 自带的三种 EXPLAIN 模式加上 query_log,看它经过了哪几层。

这条 SQL 全文用来做四次解剖SELECT id, v FROM demo.olap_batch WHERE id > 100 ORDER BY v DESC LIMIT 5

一条 SELECT 从文本变成结果,要经过:先被解析成语法树(AST),再被分析、优化成一份执行计划(Plan),再被展开成一组能并行跑的处理器(Pipeline),最后才是处理器真正读数据、算结果的执行阶段。下面四步分别是这条 SQL 在这四层的样子。

第一层:EXPLAIN AST,的语法树

SQL 文本首先被解析成一棵抽象语法树,这一步还不知道 id 是不是有索引、v 是不是能排序优化。

EXPLAIN AST SELECT id, v FROM demo.olap_batch WHERE id > 100 ORDER BY v DESC LIMIT 5SelectWithUnionQuery (children 1) ExpressionList (children 1) SelectQuery (children 5) ExpressionList (children 2) Identifier id Identifier v TablesInSelectQuery (children 1) TableIdentifier demo.olap_batch Function greater (children 1) Identifier id Literal UInt64_100 OrderByElement Identifier v Literal UInt64_5

这棵树里 WHERE id > 100 就是一个普通的 Function greater 节点,跟 ORDER BY v DESC LIMIT 5 平级摆着——语法树只管"这句话说的是什么",完全不管"应该先做哪一步、能不能用索引跳过数据"。

第二层:EXPLAIN PLAN,的执行计划

语法树被分析器和优化器处理后,变成一棵自底向上执行的计划树。

EXPLAIN PLAN SELECT id, v FROM demo.olap_batch WHERE id > 100 ORDER BY v DESC LIMIT 5Limit (preliminary LIMIT) │ Limit 5 └──Sorting (Sorting for ORDER BY) │ Sort description: v DESC │ Limit 5 └──Filter ((WHERE + Change column names)) │ Filter column: id > 100 └──ReadFromMergeTree (demo.olap_batch) Read type: Default Parts: 1 | Granules: 1

这一层已经把顺序定下来了:先 ReadFromMergeTree 读数据,再 Filter 过滤 id > 100,再 Sorting 按 v 倒排,最后 Limit 只留 5 行。而且优化器已经把 LIMIT 5 下推到了排序步骤里("Sort description ... Limit 5"),排序的时候就不用对全部结果做完整排序。

第三层:EXPLAIN PIPELINE,拼成的处理器流水线

执行计划的每一个节点会被展开成一个或多个"处理器"(Processor),这些处理器才是最终真正跑起来的东西。

EXPLAIN PIPELINE SELECT id, v FROM demo.olap_batch WHERE id > 100 ORDER BY v DESC LIMIT 5(Expression) ExpressionTransform (Limit) Limit (Sorting) MergeSortingTransform LimitsCheckingTransform PartialSortingTransform (Expression) ExpressionTransform (Filter) FilterTransform (Expression) ExpressionTransform (ReadFromMergeTree) MergeTreeSelect(pool: ReadPoolInOrder, algorithm: InOrder)

执行计划里的一个 Sorting 节点,展开成了三个处理器:PartialSortingTransform(对每个数据块局部排序)、LimitsCheckingTransform(检查资源限制)、MergeSortingTransform(把多个已排序的块归并成一个有序结果)。执行计划描述"要做什么",Pipeline 才是"具体由哪些处理器、按什么顺序真的去做"。

第四层:真正执行,query_log 里的数字

前三层都是"计划",只有真正跑起来才会在 system.query_log 里留下痕迹。

SELECT query_duration_ms, memory_usage, read_rows, result_rows FROM system.query_log WHERE type='QueryFinish' ...query_duration_ms: 4 memory_usage: 176177 read_rows: 200 result_rows: 5

执行只花了 4 毫秒,读了 200 行(因为 Granules: 1,这张小表整个只有 1 个索引颗粒,没法再细分跳过),最终返回 5 行,占用了约 172 KiB 内存。前面三层看到的 AST、Plan、Pipeline 都只是"计划应该怎么做",这一步的四个数字才是"真的做了多少"。

分步演示:一条SQL的四层生命周期

每一步都是本文上面用EXPLAIN和query_log拆出来的原始结果。

同一条SQL,经过AST→Plan→Pipeline→执行的四层
这一步新验证的层

    本文用到的工具

    • EXPLAIN AST / EXPLAIN PLAN / EXPLAIN PIPELINE:ClickHouse 自带的三种解剖视角
    • system.query_log:执行后的耗时、内存、读取行数
    京ICP备2026067502号-1京公网安备11010502063487号