使用分析器理解查询执行
ClickHouse 处理查询的速度极快,但查询的执行并不是简单的事情。让我们尝试理解一个 SELECT
查询是如何被执行的。为了说明这一点,让我们在 ClickHouse 中的表中添加一些数据:
现在我们在 ClickHouse 中有了一些数据,我们想要运行一些查询并理解它们的执行。查询的执行分解为许多步骤。查询执行的每一步都可以使用相应的 EXPLAIN
查询进行分析和故障排除。这些步骤在下面的图表中进行了总结:

让我们在查询执行过程中观察每个实体的作用。我们将对几个查询进行分析,然后使用 EXPLAIN
语句来检查它们。
解析器
解析器的目标是将查询文本转换为AST(抽象语法树)。这个步骤可以通过 EXPLAIN AST
可视化:
输出是一个抽象语法树,可以如下所示:

每个节点都有相应的子节点,整个树表示查询的整体结构。这是一个逻辑结构,有助于处理查询。从最终用户的角度来看(除非对查询执行感兴趣),这并不是非常有用;这个工具主要用于开发者。
分析器
ClickHouse 当前有两种架构供分析器使用。您可以通过设置 enable_analyzer=0
来使用旧架构。默认情况下启用新架构。我们将在此描述新架构,因为旧架构将在新分析器普遍可用之后弃用。
新架构应该为我们提供一个更好的框架,以提高 ClickHouse 的性能。然而,由于它是查询处理步骤的基本组成部分,它也可能对某些查询产生负面影响,并且存在 已知的不兼容性。您可以通过在查询或用户级别更改 enable_analyzer
设置来恢复到旧分析器。
分析器是查询执行的重要步骤。它接受AST并将其转换为查询树。查询树相对于AST的主要好处是许多组件将被解析,例如存储。例如,我们还知道从哪个表读取,别名也被解析,树知道不同的数据类型。通过这些好处,分析器可以应用优化。这些优化的工作方式是通过“遍历”。每个遍历将寻找不同的优化。您可以在 这里 看到所有的遍历,我们来对之前的查询进行实践:
在两个执行之间,您可以看到别名和投影的解析。
规划器
规划器将查询树转换为查询计划。查询树告诉我们想对特定查询做什么,而查询计划告诉我们将如何执行。查询计划中还将进行额外的优化。您可以使用 EXPLAIN PLAN
或 EXPLAIN
来查看查询计划(EXPLAIN
将执行 EXPLAIN PLAN
)。
尽管这给我们提供了一些信息,但我们可以获取更多信息。例如,也许我们想知道需要哪些列名来执行投影。您可以将标题添加到查询中:
现在您知道最后一个投影(minimum_date
、maximum_date
和 percentage
)需要创建哪些列名,但您可能还想知道所有需要执行的操作的详细信息。您可以通过设置 actions=1
来实现。
您现在可以看到所有的输入、函数、别名和正在使用的数据类型。您可以在 这里 查看规划器将要应用的一些优化。
查询管道
查询管道是从查询计划生成的。查询管道与查询计划非常相似,不同之处在于它不是树,而是图。它突出了 ClickHouse 将如何执行查询以及将使用哪些资源。分析查询管道非常有助于了解在输入/输出方面的瓶颈在哪里。我们对之前的查询进行分析,并查看查询管道的执行:
括号内是查询计划步骤,旁边是处理器。这是很有用的信息,但由于这是一个图,能够可视化它会很不错。我们有一个设置 graph
可以设置为 1,并指定输出格式为 TSV:
然后您可以复制这个输出并粘贴到 这里,它将生成以下图形:

白色矩形对应于一个管道节点,灰色矩形对应于查询计划步骤,后面的 x
和数字对应于正在使用的输入/输出的数量。如果您不想在紧凑形式中看到它们,您可以随时添加 compact=0
:

为什么 ClickHouse 不使用多个线程从表中读取数据?让我们尝试在表中添加更多数据:
现在让我们再次运行我们的 EXPLAIN
查询:

所以执行器决定不并行化操作,因为数据量不够大。通过添加更多行,执行器决定使用多个线程,如图所示。
执行器
查询执行的最后一步由执行器完成。它将接受查询管道并执行它。根据您是否执行 SELECT
、INSERT
或 INSERT SELECT
,执行器有不同类型。