分析查询计划
了解如何读取和分析查询计划,以理解查询执行步骤和数据组织,并找到性能瓶颈。
当您查询 InfluxDB 3 时,查询器会设计一个查询计划来执行查询。引擎会尝试为查询结构和数据确定最佳计划。通过学习如何生成和解释查询计划的报告,您可以更好地理解查询是如何执行的,并识别影响查询性能的瓶颈。
例如,如果查询计划显示您的查询读取了大量 Parquet 文件,您可以采取措施优化您的查询,例如添加过滤器以读取更少的数据,或配置您的集群以存储更少但更大的文件。
使用 EXPLAIN 关键字查看查询计划
使用 EXPLAIN
关键字(以及可选的 ANALYZE
和 VERBOSE
关键字)来查看查询的查询计划。
阅读 EXPLAIN 报告
当您使用 EXPLAIN
关键字查看查询计划时,报告包含以下内容
阅读查询计划
计划采用树状格式——每个计划都是一个倒置的树,其中执行和数据流从叶节点(计划中最内层的步骤)流向外部分支节点。 无论是阅读逻辑计划还是物理计划,请记住以下几点
- 从叶节点开始,向上阅读。
- 在计划的顶部,根节点代表最终的、包含所有步骤的步骤。
在物理计划中,每个步骤都是一个ExecutionPlan
节点,它接收输入数据和输出需求的表达式,并计算数据分区。
使用以下步骤分析查询计划,并估计完成查询所需的工作量。无论计划看起来多么庞大或复杂,这些步骤都适用。
- 从最深缩进的步骤(叶节点)开始,向上阅读。
- 理解每个
ExecutionPlan
节点的工作——例如,包含叶节点的UnionExec
节点意味着UnionExec
连接所有叶节点的输出。 - 对于每个表达式,回答以下问题
- 计划的数据输入的形状和大小是什么?
- 计划的数据输出的形状和大小是什么?
本指南的其余部分将引导您分析物理计划。 理解查询计划中节点的顺序、角色、输入和输出可以帮助您估计总体工作负载,并找到查询中的潜在瓶颈。
SELECT - ORDER BY 查询的物理计划示例
以下示例展示了如何读取 EXPLAIN
报告和物理查询计划。
给定 h20
测量数据和以下查询
EXPLAIN SELECT city, min_temp, time FROM h2o ORDER BY city ASC, time DESC;
输出类似于以下内容
EXPLAIN 报告
| plan_type | plan |
+---------------+--------------------------------------------------------------------------+
| logical_plan | Sort: h2o.city ASC NULLS LAST, h2o.time DESC NULLS FIRST |
| | TableScan: h2o projection=[city, min_temp, time] |
| physical_plan | SortPreservingMergeExec: [city@0 ASC NULLS LAST,time@2 DESC] |
| | UnionExec |
| | SortExec: expr=[city@0 ASC NULLS LAST,time@2 DESC] |
| | ParquetExec: file_groups={...}, projection=[city, min_temp, time] |
| | SortExec: expr=[city@0 ASC NULLS LAST,time@2 DESC] |
| | ParquetExec: file_groups={...}, projection=[city, min_temp, time] |
| | |
EXPLAIN SELECT city, min_temp, time FROM h2o ORDER BY city ASC, time DESC;
的输出
物理计划中的每个步骤或节点都是一个 ExecutionPlan
名称和包含查询相关部分的键值表达式——例如,EXPLAIN
报告物理计划中的第一个节点是 ParquetExec
执行计划
ParquetExec: file_groups={...}, projection=[city, min_temp, time]
由于 ParquetExec
和 RecordBatchesExec
节点在 InfluxDB 查询中检索和扫描数据,因此每个查询计划都以一个或多个这些节点开始。
物理计划数据流
数据在查询计划中向上流动。
下图显示了EXPLAIN
报告物理计划中的数据流和节点顺序
SortPreservingMergeExec
UnionExec
SortExec
ParquetExec
SortExec
ParquetExec
EXPLAIN
报告物理计划中的执行和数据流。 ParquetExec
节点并行执行,UnionExec
组合它们的输出。
以下步骤总结了物理计划执行和数据流
- 两个
ParquetExec
计划并行从 Parquet 文件中读取数据- 每个
ParquetExec
节点处理一个或多个文件组。 - 每个文件组包含一个或多个 Parquet 文件路径。
ParquetExec
节点并行处理其组,顺序读取每个组的文件。- 输出是数据流到相应的
SortExec
节点。
- 每个
SortExec
节点并行地按city
(升序)和time
(降序)对数据进行排序。SortPreservingMergeExec
计划需要排序。UnionExec
节点连接数据流以联合并行SortExec
节点的输出。SortPreservingMergeExec
节点合并来自UnionExec
的先前排序和联合的数据。
空结果集的 EXPLAIN
报告示例
如果您的表不包含查询时间范围内的数据,则物理计划以 EmptyExec
叶节点开始——例如
ProjectionExec: expr=[temp@0 as temp]
SortExec: expr=[time@1 ASC NULLS LAST]
EmptyExec: produce_one_row=false
分析前沿数据的查询计划
以下章节将指导您分析典型时间序列用例的物理查询计划——聚合最近写入的(前沿)数据。 尽管查询和计划比前面的示例更复杂,但您将遵循相同的步骤来读取查询计划。 在学习如何读取查询计划后,您将了解 ExecutionPlans
、数据流和潜在的查询瓶颈。
示例数据
考虑以下 h20
数据,表示为写入 InfluxDB 的 Line Protocol “块”
// h20 data
// The following data represents 5 batches, or "chunks", of line protocol
// written to InfluxDB.
// - Chunks 1-4 are ingested and each is persisted to a separate partition file in storage.
// - Chunk 5 is ingested and not yet persisted to storage.
// - Chunks 1 and 2 cover short windows of time that don't overlap times in other chunks.
// - Chunks 3 and 4 cover larger windows of time and the time ranges overlap each other.
// - Chunk 5 contains the largest time range and overlaps with chunk 4, the Parquet file with the largest time-range.
// - In InfluxDB, a chunk never duplicates its own data.
//
// Chunk 1: stored Parquet file
// - time range: 50-249
// - no duplicates in its own chunk
// - no overlap with any other chunks
[
"h2o,state=MA,city=Bedford min_temp=71.59 150",
"h2o,state=MA,city=Boston min_temp=70.4, 50",
"h2o,state=MA,city=Andover max_temp=69.2, 249",
],
// Chunk 2: stored Parquet file
// - time range: 250-349
// - no duplicates in its own chunk
// - no overlap with any other chunks
// - adds a new field (area)
[
"h2o,state=CA,city=SF min_temp=79.0,max_temp=87.2,area=500u 300",
"h2o,state=CA,city=SJ min_temp=75.5,max_temp=84.08 349",
"h2o,state=MA,city=Bedford max_temp=78.75,area=742u 300",
"h2o,state=MA,city=Boston min_temp=65.4 250",
],
// Chunk 3: stored Parquet file
// - time range: 350-500
// - no duplicates in its own chunk
// - overlaps chunk 4
[
"h2o,state=CA,city=SJ min_temp=77.0,max_temp=90.7 450",
"h2o,state=CA,city=SJ min_temp=69.5,max_temp=88.2 500",
"h2o,state=MA,city=Boston min_temp=68.4 350",
],
// Chunk 4: stored Parquet file
// - time range: 400-600
// - no duplicates in its own chunk
// - overlaps chunk 3
[
"h2o,state=CA,city=SF min_temp=68.4,max_temp=85.7,area=500u 600",
"h2o,state=CA,city=SJ min_temp=69.5,max_temp=89.2 600", // duplicates row 3 in chunk 5
"h2o,state=MA,city=Bedford max_temp=80.75,area=742u 400", // overlaps chunk 3
"h2o,state=MA,city=Boston min_temp=65.40,max_temp=82.67 400", // overlaps chunk 3
],
// Chunk 5: Ingester data
// - time range: 550-700
// - overlaps and duplicates data in chunk 4
[
"h2o,state=MA,city=Bedford max_temp=88.75,area=742u 600", // overlaps chunk 4
"h2o,state=CA,city=SF min_temp=68.4,max_temp=85.7,area=500u 650",
"h2o,state=CA,city=SJ min_temp=68.5,max_temp=90.0 600", // duplicates row 2 in chunk 4
"h2o,state=CA,city=SJ min_temp=75.5,max_temp=84.08 700",
"h2o,state=MA,city=Boston min_temp=67.4 550", // overlaps chunk 4
]
以下查询选择所有数据
SELECT state, city, min_temp, max_temp, area, time
FROM h2o
ORDER BY state asc, city asc, time desc;
输出如下
+-------+---------+----------+----------+------+--------------------------------+
| state | city | min_temp | max_temp | area | time |
+-------+---------+----------+----------+------+--------------------------------+
| CA | SF | 68.4 | 85.7 | 500 | 1970-01-01T00:00:00.000000650Z |
| CA | SF | 68.4 | 85.7 | 500 | 1970-01-01T00:00:00.000000600Z |
| CA | SF | 79.0 | 87.2 | 500 | 1970-01-01T00:00:00.000000300Z |
| CA | SJ | 75.5 | 84.08 | | 1970-01-01T00:00:00.000000700Z |
| CA | SJ | 68.5 | 90.0 | | 1970-01-01T00:00:00.000000600Z |
| CA | SJ | 69.5 | 88.2 | | 1970-01-01T00:00:00.000000500Z |
| CA | SJ | 77.0 | 90.7 | | 1970-01-01T00:00:00.000000450Z |
| CA | SJ | 75.5 | 84.08 | | 1970-01-01T00:00:00.000000349Z |
| MA | Andover | | 69.2 | | 1970-01-01T00:00:00.000000249Z |
| MA | Bedford | | 88.75 | 742 | 1970-01-01T00:00:00.000000600Z |
| MA | Bedford | | 80.75 | 742 | 1970-01-01T00:00:00.000000400Z |
| MA | Bedford | | 78.75 | 742 | 1970-01-01T00:00:00.000000300Z |
| MA | Bedford | 71.59 | | | 1970-01-01T00:00:00.000000150Z |
| MA | Boston | 67.4 | | | 1970-01-01T00:00:00.000000550Z |
| MA | Boston | 65.4 | 82.67 | | 1970-01-01T00:00:00.000000400Z |
| MA | Boston | 68.4 | | | 1970-01-01T00:00:00.000000350Z |
| MA | Boston | 65.4 | | | 1970-01-01T00:00:00.000000250Z |
| MA | Boston | 70.4 | | | 1970-01-01T00:00:00.000000050Z |
+-------+---------+----------+----------+------+--------------------------------+
示例查询
以下查询从示例数据中选择前沿数据
SELECT city, count(1)
FROM h2o
WHERE time >= to_timestamp(200) AND time < to_timestamp(700)
AND state = 'MA'
GROUP BY city
ORDER BY city ASC;
输出如下
+---------+-----------------+
| city | COUNT(Int64(1)) |
+---------+-----------------+
| Andover | 1 |
| Bedford | 3 |
| Boston | 4 |
+---------+-----------------+
前沿数据查询的 EXPLAIN 报告
以下查询为前面的示例查询生成 EXPLAIN
报告
EXPLAIN SELECT city, count(1)
FROM h2o
WHERE time >= to_timestamp(200) AND time < to_timestamp(700)
AND state = 'MA'
GROUP BY city
ORDER BY city ASC;
示例数据中的注释告诉您哪些数据块重叠或重复其他数据块中的数据。 如果存在数据块中都存在数据的时间段,则两个数据块重叠。 您将在本指南的后面学习如何在查询计划中识别重叠和重复数据。
与示例数据不同,您的数据可能不会告诉您重叠或重复存在的位置。 物理计划可以揭示数据中的重叠和重复,以及它们如何影响您的查询——例如,在学习如何读取物理计划后,您可以将数据扫描步骤总结如下
- 查询执行从两个
ParquetExec
和一个RecordBatchesExec
执行计划开始,这些计划并行运行。 - 第一个
ParquetExec
节点读取两个不与任何其他文件重叠且不重复数据的文件; 这些文件不需要去重。 - 第二个
ParquetExec
节点读取两个相互重叠的文件,并与RecordBatchesExec
节点中扫描的摄取数据重叠; 查询计划必须在完成查询之前包含这些节点的去重过程。
其余部分分析示例物理计划中的 ExecutionPlan
节点结构和参数。 该示例包括 DataFusion 和 InfluxDB 特定的 ExecutionPlan
节点。
定位物理计划
要开始分析查询的物理计划,请在EXPLAIN
报告中找到 plan_type
列值为 physical_plan
的行。 该行的 plan
列包含物理计划。
阅读物理计划
以下部分遵循读取查询计划的步骤,并检查物理计划节点及其输入和输出。
要读取查询计划的执行流程,始终从最内层(叶)节点开始,向上读取到最外层的根节点。
物理计划叶节点

物理计划中叶节点的结构
数据扫描节点 (ParquetExec 和 RecordBatchesExec)
ParquetExec
节点从对象存储中的 Parquet 文件中检索和扫描数据RecordBatchesExec
节点从摄取器中检索最近写入但尚未持久化的数据
由于 ParquetExec
和 RecordBatchesExec
检索和扫描查询的数据,因此每个查询计划都以一个或多个这些节点开始。
ParquetExec
和 RecordBatchesExec
节点的数量及其参数值可以告诉您为查询检索了哪些数据(以及多少数据),以及计划如何有效地处理数据的组织(例如,分区和去重)。
为方便起见,本指南使用名称 ParquetExec_A 和 ParquetExec_B 来表示示例物理计划中的 ParquetExec
节点。 从物理计划的顶部开始读取,ParquetExec_A 是物理计划中的第一个叶节点,ParquetExec_B 是最后一个(底部)叶节点。
这些名称指示节点在报告中的位置,而不是它们的执行顺序。
ParquetExec_A
ParquetExec: file_groups={2 groups: [[1/1/b862a7e9b329ee6a418cde191198eaeb1512753f19b87a81def2ae6c3d0ed237/243db601-f3f1-401b-afda-82160d8cc1a8.Parquet], [1/1/b862a7e9b329ee6a418cde191198eaeb1512753f19b87a81def2ae6c3d0ed237/f5fb7c7d-16ac-49ba-a811-69578d05843f.Parquet]]}, projection=[city, state, time], output_ordering=[state@1 ASC, city@0 ASC, time@2 ASC], predicate=time@5 >= 200 AND time@5 < 700 AND state@4 = MA, pruning_predicate=time_max@0 >= 200 AND time_min@1 < 700 AND state_min@2 <= MA AND MA <= state_max@3 |
ParquetExec_A,第一个 ParquetExec 节点
ParquetExec_A 具有以下特征
file_groups
文件组是运算符要读取的文件列表。 文件通过路径引用
1/1/b862a7e9b.../243db601-....parquet
1/1/b862a7e9b.../f5fb7c7d-....parquet
路径结构表示数据的组织方式。 您可以使用文件路径来收集有关查询的更多信息——例如
- 在目录中查找文件信息(例如:大小和行数)
- 从对象存储下载 Parquet 文件以进行调试
- 查找查询读取的分区数
路径具有以下结构
<namespace_id>/<table_id>/<partition_hash_id>/<uuid_of_the_file>.Parquet
1 / 1 /b862a7e9b329ee6a4.../243db601-f3f1-4....Parquet
namespace_id
:正在查询的命名空间(数据库)table_id
:正在查询的表(测量)partition_hash_id
:此文件所属的分区。 您可以计算分区 ID 以查找查询读取的分区数。uuid_of_the_file
:文件标识符。
ParquetExec
并行处理组,并顺序读取每个组中的文件。
file_groups={2 groups: [[1/1/b862a7e9b329ee6a4/243db601....parquet], [1/1/b862a7e9b329ee6a4/f5fb7c7d....parquet]]}
{2 groups: [[file], [file]}
:ParquetExec_A 接收两个组,每个组包含一个文件。 因此,ParquetExec_A 并行读取两个文件。
projection
projection
列出了 ExecutionPlan
要读取和输出的表列。
projection=[city, state, time]
output_ordering
output_ordering
指定 ExecutionPlan
输出的排序顺序。 如果输出应排序并且计划器知道顺序,则查询计划器会传递此参数。
output_ordering=[state@2 ASC, city@1 ASC, time@3 ASC, __chunk_order@0 ASC]
在将数据存储到 Parquet 文件时,InfluxDB 会对数据进行排序以提高存储压缩和查询效率,并且计划器会尝试尽可能长时间地保留该顺序。 通常,ParquetExec
接收的 output_ordering
值是存储数据的排序(或排序的子集)。
根据设计,RecordBatchesExec
数据未排序。
在示例中,计划器指定 ParquetExec_A 使用现有的排序顺序 state ASC, city ASC, time ASC,
进行输出。
要查看存储数据的排序顺序,请为 SELECT ALL
查询生成 EXPLAIN
报告——例如
EXPLAIN SELECT * FROM TABLE_NAME WHERE time > now() - interval '1 hour'
如果查询返回的数据过多,请缩短时间范围。
predicate
predicate
是查询中指定的数据过滤器。
predicate=time@5 >= 200 AND time@5 < 700 AND state@4 = MA
pruning predicate
pruning_predicate
是从 predicate
值创建的,并且是实际用于从选定分区中剪枝数据和文件的谓词。 默认过滤器按 time
过滤文件。
pruning_predicate=time_max@0 >= 200 AND time_min@1 < 700 AND state_min@2 <= MA AND MA <= state_max@3
在生成物理计划之前,一个额外的 partition pruning
步骤使用分区列上的谓词来剪枝分区。
RecordBatchesExec
RecordBatchesExec: chunks=1, projection=[__chunk_order, city, state, time]
RecordBatchesExec
是 InfluxDB 特定的 ExecutionPlan
实现,用于从摄取器中检索最近写入但尚未持久化的数据。
在示例中,RecordBatchesExec
包含以下表达式
chunks
chunks
是从摄取器接收的数据块的数量。
chunks=1
chunks=1
:RecordBatchesExec
接收一个数据块。
projection
projection
列表指定节点要读取和输出的列或表达式。
[__chunk_order, city, state, time]
__chunk_order
:为去重排序块和文件city, state, time
:与ParquetExec_A projection
中指定的列相同
数据扫描节点中 __chunk_order
的存在表明节点之间存在数据重叠,并且可能重复。
ParquetExec_B
示例物理计划中的底部叶节点是另一个 ParquetExec
运算符,ParquetExec_B。
ParquetExec_B 表达式
ParquetExec:
file_groups={2 groups: [[1/1/b862a7e9b.../2cbb3992-....Parquet],
[1/1/b862a7e9b.../9255eb7f-....Parquet]]},
projection=[__chunk_order, city, state, time],
output_ordering=[state@2 ASC, city@1 ASC, time@3 ASC, __chunk_order@0 ASC],
predicate=time@5 >= 200 AND time@5 < 700 AND state@4 = MA,
pruning_predicate=time_max@0 >= 200 AND time_min@1 < 700 AND state_min@2 <= MA AND MA <= state_max@3
由于 ParquetExec_B 存在重叠,因此 projection
和 output_ordering
表达式使用 RecordBatchesExec
projection
中使用的 __chunk_order
列。
数据扫描节点中 __chunk_order
的存在表明节点之间存在数据重叠,并且可能重复。
其余 ParquetExec_B 表达式与 ParquetExec_A 中的表达式类似。
查询计划如何分发数据以进行扫描
如果您比较file_group
路径在 ParquetExec_A 和 ParquetExec_B 中的路径,您会注意到两者都包含来自同一分区的文件
1/1/b862a7e9b329ee6a4.../...
计划器可能会将来自同一分区的文件分发到不同的扫描节点,原因有多种,包括处理重叠的优化——例如
- 将非重叠文件与重叠文件分开,以最大限度地减少去重所需的工作量(在本示例中就是这种情况)
- 分发非重叠文件以增加并行执行
分析分支结构
从数据扫描节点输出数据后,数据会向上流到下一个父(外部)节点。
在示例计划中
- 每个叶节点都是为处理扫描数据而计划的节点分支中的第一步。
- 这三个分支并行执行。
- 在叶节点之后,每个分支都包含以下类似的节点结构
...
CoalesceBatchesExec: target_batch_size=8192
FilterExec: time@3 >= 200 AND time@3 < 700 AND state@2 = MA
...
FilterExec: time@3 >= 200 AND time@3 < 700 AND state@2 = MA
:为条件time@3 >= 200 AND time@3 < 700 AND state@2 = MA
过滤数据,并保证所有数据都被剪枝。CoalesceBatchesExec: target_batch_size=8192
:将小批量合并为大批量。 请参阅 DataFusion [CoalesceBatchesExec
] 文档。
排序尚未持久化的数据
在 RecordBatchesExec
分支中,CoalesceBatchesExec
之后的节点是 SortExec
节点
SortExec: expr=[state@2 ASC,city@1 ASC,time@3 ASC,__chunk_order@0 ASC]
该节点使用指定的表达式 state ASC, city ASC, time ASC, __chunk_order ASC
对尚未持久化的数据进行排序。 ParquetExec_A 和 ParquetExec_B 都不包含类似的节点,因为对象存储中的数据已经按给定顺序排序(由 摄取器 或 压缩器); 查询计划只需要对来自摄取器的数据进行排序。
识别重叠和重复数据
在物理计划示例中,ParquetExec_B 和 RecordBatchesExec
节点共享以下父节点
...
DeduplicateExec: [state@2 ASC,city@1 ASC,time@3 ASC]
SortPreservingMergeExec: [state@2 ASC,city@1 ASC,time@3 ASC,__chunk_order@0 ASC]
UnionExec
...
UnionExec
:通过连接分区来联合多个输入数据流。UnionExec
不执行任何合并操作,执行速度很快。SortPreservingMergeExec: [state@2 ASC,city@1 ASC,time@3 ASC,__chunk_order@0 ASC]
:合并已排序的数据;表明先前的数据(来自其下方的节点)已排序。输出数据是单个排序流。DeduplicateExec: [state@2 ASC,city@1 ASC,time@3 ASC]
:对已排序的输入数据流进行去重。由于SortPreservingMergeExec
确保单个排序流,因此它通常(但并非总是)在DeduplicateExec
之前。
DeduplicateExec
节点表明包含的节点具有重叠数据——文件或批次中的数据与另一个文件或批次中的数据的时间戳范围相同。由于 InfluxDB 组织数据的方式,数据永远不会在文件内部重复。
在示例中,DeduplicateExec
节点包含 ParquetExec_B 和 RecordBatchesExec
节点,这表明 ParquetExec_B 文件组 文件与尚未持久化的数据重叠。
以下示例数据摘录显示了文件和 Ingester 数据之间的重叠数据
// Chunk 4: stored Parquet file
// - time range: 400-600
[
"h2o,state=CA,city=SF min_temp=68.4,max_temp=85.7,area=500u 600",
],
// Chunk 5: Ingester data
// - time range: 550-700
// - overlaps and duplicates data in chunk 4
[
"h2o,state=MA,city=Bedford max_temp=88.75,area=742u 600", // overlaps chunk 4
...
"h2o,state=MA,city=Boston min_temp=67.4 550", // overlaps chunk 4
]
如果文件或摄取的数据重叠,则 Querier 必须在查询计划中包含 DeduplicateExec
以删除任何重复项。DeduplicateExec
不一定表示数据重复。如果计划读取许多文件并对所有文件执行去重,则可能是出于以下原因
- 文件包含重复数据
- 对象存储中有许多 Compactor 尚未压缩的小型重叠文件。压缩后,您的查询性能可能会更好,因为它需要读取的文件更少
- Compactor 跟不上进度。如果数据未重复,并且压缩后仍然有许多小型重叠文件,那么您可能需要检查 Compactor 的工作负载并根据需要添加更多资源
分支中没有 DeduplicateExec
节点的叶节点不需要去重,也不会与其他文件或 Ingester 数据重叠——例如,ParquetExec_A 没有重叠
ProjectionExec:...
CoalesceBatchesExec:...
FilterExec:...
ParquetExec:...
缺少 DeduplicateExec
节点意味着文件不重叠。
数据扫描输出
ProjectionExec
节点过滤列,以便输出中仅保留 city
列
`ProjectionExec: expr=[city@0 as city]`
最终处理
在每个叶节点中去重和过滤数据后,计划将合并输出,然后应用聚合和排序运算符以获得最终结果
| physical_plan | SortPreservingMergeExec: [city@0 ASC NULLS LAST] |
| | SortExec: expr=[city@0 ASC NULLS LAST] |
| | AggregateExec: mode=FinalPartitioned, gby=[city@0 as city], aggr=[COUNT(Int64(1))] |
| | CoalesceBatchesExec: target_batch_size=8192 |
| | RepartitionExec: partitioning=Hash([city@0], 4), input_partitions=4 |
| | AggregateExec: mode=Partial, gby=[city@0 as city], aggr=[COUNT(Int64(1))] |
| | RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=3 |
| | UnionExec
用于聚合、排序和最终输出的运算符结构。
UnionExec
:联合数据流。请注意,输出流的数量与输入流的数量相同——UnionExec
节点是下游运算符的中间步骤,下游运算符实际合并或拆分数据流。RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=3
:以轮询方式将三个输入流拆分为四个输出流。该计划拆分流以提高并行执行。AggregateExec: mode=Partial, gby=[city@0 as city], aggr=[COUNT(Int64(1))]
:按照查询中指定的进行数据分组:city, count(1)
。此节点分别聚合四个流中的每一个,然后输出四个流,由mode=Partial
指示——数据未完全聚合。RepartitionExec: partitioning=Hash([city@0], 4), input_partitions=4
:在Hash([city])
上重新分区数据,并分成四个流——每个流包含一个城市的数据。AggregateExec: mode=FinalPartitioned, gby=[city@0 as city], aggr=[COUNT(Int64(1))]
:对数据应用最终聚合 (aggr=[COUNT(Int64(1))]
)。mode=FinalPartitioned
表示数据已经分区(按城市),不需要AggregateExec
进一步分组。SortExec: expr=[city@0 ASC NULLS LAST]
:按照查询中的指定,对四个数据流进行排序,每个流都按city
排序。SortPreservingMergeExec: [city@0 ASC NULLS LAST]
:合并和排序四个已排序的流,以获得最终输出。
在前面的示例中,EXPLAIN
报告显示了查询计划,但未执行查询。要查看运行时指标,例如计划及其运算符的执行时间,请使用 EXPLAIN ANALYZE
生成报告,并在必要时使用 跟踪 进行进一步调试。
此页内容是否对您有帮助?
感谢您的反馈!
支持和反馈
感谢您成为我们社区的一份子!我们欢迎并鼓励您提供关于 InfluxDB Clustered 和此文档的反馈和错误报告。要获得支持,请使用以下资源
拥有年度或支持合同的客户可以联系 InfluxData 支持。