| <!-- |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| |
| --> |
| # 查询性能分析 |
| |
| ## 1. 概述 |
| |
| 查询分析用于帮助用户理解查询的执行机制和性能瓶颈,从而进行查询优化和性能调优。IoTDB 表模型提供两类查询分析语句: |
| |
| - `EXPLAIN`:预览查询 SQL 的执行计划,展示 IoTDB 如何组织数据检索和处理。 |
| |
| - `EXPLAIN ANALYZE`:在 `EXPLAIN` 基础上真实执行查询,并展示查询执行过程中的时间、资源消耗和算子统计信息。 |
| |
| `EXPLAIN` 和 `EXPLAIN ANALYZE` 默认输出面向人工阅读,适合在 CLI 中直接查看。对于 Web Console、CI 回归测试、自动化性能诊断系统等需要稳定解析查询计划或执行统计的场景,可以使用 JSON 输出格式获取结构化结果。JSON 格式自 V2.0.11 起支持。 |
| |
| ### 1.1 查询分析方式对比 |
| |
| 与 Arthas 抽样等排查手段相比,`EXPLAIN ANALYZE` 无需部署额外组件,可以针对单条 SQL 进行分布式追踪,更适合定位具体查询的性能问题。 |
| |
| |方法|安装难度|业务影响|功能范围| |
| |---|---|---|---| |
| |`EXPLAIN ANALYZE` 语句|低。无需安装额外组件,为 IoTDB 内置 SQL 语句|低。只会影响当前分析的单条查询,对线上其他负载无影响|支持分布式,可对单条 SQL 进行追踪| |
| |Arthas 抽样|中。需要安装 Java Arthas 工具|高。CPU 抽样可能会影响线上业务响应速度|不支持分布式,仅支持对数据库整体查询负载和耗时进行分析| |
| |
| ## 2. EXPLAIN |
| |
| ### 2.1 语法 |
| |
| `EXPLAIN` 命令用于查看 SQL 查询的分布式执行计划。执行计划以算子树的形式展示,描述 IoTDB 将如何执行查询。 |
| |
| ```SQL |
| EXPLAIN [(FORMAT { GRAPHVIZ | JSON })] <SELECT_STATEMENT> |
| ``` |
| |
| 其中: |
| |
| |参数|说明| |
| |---|---| |
| |`SELECT_STATEMENT`|需要分析的查询语句| |
| |`FORMAT GRAPHVIZ`|以默认图形文本形式输出分布式计划,适合人工阅读| |
| |`FORMAT JSON`|以 JSON 对象输出分布式计划,适合程序解析(自 V2.0.11 起支持)| |
| |
| `FORMAT` 后的格式名大小写不敏感,例如 `FORMAT json` 与 `FORMAT JSON` 等价。 |
| |
| ### 2.2 默认 GRAPHVIZ 格式 |
| |
| `EXPLAIN` 默认格式为 `GRAPHVIZ`,执行后将得到 `distribution plan` 结果列。 |
| |
| 以[示例数据](../Reference/Sample-Data.md)中的 `table1` 为例,以下两条语句等价: |
| |
| ```SQL |
| EXPLAIN SELECT * FROM table1; |
| EXPLAIN (FORMAT GRAPHVIZ) SELECT * FROM table1; |
| ``` |
| |
| 执行如上语句后,输出如下:IoTDB 通过 `DeviceTableScanNode` 节点从不同数据分区读取数据,并通过 `Collect` 算子汇总后返回。 |
| |
| ```SQL |
| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
| | distribution plan| |
| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
| | ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | |
| | │OutputNode-4 │ | |
| | │OutputColumns-[time, region, plant_id, device_id, model_id, maintenance, temperature, humidity, status, arrival_time] │ | |
| | │OutputSymbols: [time, region, plant_id, device_id, model_id, maintenance, temperature, humidity, status, arrival_time]│ | |
| | └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ | |
| | │ | |
| | │ | |
| | ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | |
| | │Collect-33 │ | |
| | │OutputSymbols: [time, region, plant_id, device_id, model_id, maintenance, temperature, humidity, status, arrival_time]│ | |
| | └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ | |
| | ┌───────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────┐ | |
| | │ │ | |
| | ┌───────────┐ ┌───────────┐ | |
| | │Exchange-40│ │Exchange-41│ | |
| | └───────────┘ └───────────┘ | |
| | │ │ | |
| | │ │ | |
| |┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐| |
| |│DeviceTableScanNode-32 │ │DeviceTableScanNode-31 │| |
| |│QualifiedTableName: database1.table1 │ │QualifiedTableName: database1.table1 │| |
| |│OutputSymbols: [time, region, plant_id, device_id, model_id, maintenance, temperature, humidity, status, arrival_time]│ │OutputSymbols: [time, region, plant_id, device_id, model_id, maintenance, temperature, humidity, status, arrival_time]│| |
| |│DeviceNumber: 4 │ │DeviceNumber: 2 │| |
| |│ScanOrder: ASC │ │ScanOrder: ASC │| |
| |│PushDownOffset: 0 │ │PushDownOffset: 0 │| |
| |│PushDownLimit: 0 │ │PushDownLimit: 0 │| |
| |│PushDownLimitToEachDevice: false │ │PushDownLimitToEachDevice: false │| |
| |│RegionId: 1 │ │RegionId: 2 │| |
| |└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘| |
| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
| ``` |
| |
| ### 2.3 JSON 格式 |
| |
| 使用 `EXPLAIN (FORMAT JSON)` 可以返回分布式计划树的 JSON 表示。结果集为单列输出,JSON 格式下返回单行、单个 JSON 对象,便于 JDBC 客户端或自动化工具直接读取。 |
| |
| `EXPLAIN (FORMAT JSON)` 的顶层结构随查询类型变化: |
| |
| |场景|顶层结构|说明| |
| |---|---|---| |
| |普通查询|plan node JSON object|顶层直接是 `OutputNode` 等计划节点对象| |
| |包含 materialized CTE 的查询|wrapper JSON object|顶层包含 `cteQueries` 和 `mainQuery`,用于同时保留 CTE 子查询计划与主查询计划| |
| |
| 每个 plan node 输出为一个 JSON object,基础字段如下: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`name`|string|节点类型与 plan node id 拼接后的展示名,例如 `OutputNode-4`| |
| |`id`|string|plan node id| |
| |`properties`|object|节点属性。仅当节点存在可展示属性时输出| |
| |`children`|array|子节点数组。仅当节点存在子节点时输出| |
| |
| 常见 plan node 属性包括: |
| |
| |节点类型|主要字段/属性| |
| |---|---| |
| |`OutputNode`|`OutputColumns`、`OutputSymbols`| |
| |`TableScanNode` / `DeviceTableScanNode`|`QualifiedTableName`、`OutputSymbols`、`DeviceNumber`、`ScanOrder`、`TimePredicate`、`PushDownPredicate`、`PushDownOffset`、`PushDownLimit`、`PushDownLimitToEachDevice`、`RegionId`| |
| |`TreeDeviceViewScanNode`|除表扫描属性外,补充 `TreeDB`、`MeasurementToColumnName`| |
| |`AggregationNode`|`OutputSymbols`、`Aggregators`、`GroupingKeys`、`Streamable`、`PreGroupedSymbols`、`Step`| |
| |`FilterNode`|`Predicate`| |
| |`ProjectNode`|`OutputSymbols`、`Expressions`| |
| |`LimitNode` / `OffsetNode`|`Count`| |
| |`SortNode` / `MergeSortNode`|`OrderBy`| |
| |`JoinNode`|`JoinType`、`Criteria`、`OutputSymbols`| |
| |`UnionNode`|`OutputSymbols`| |
| |`ExplainAnalyzeNode`|`ChildPermittedOutputs`| |
| |
| 当查询包含 materialized CTE 时,JSON 顶层不再直接是单个 plan node,而是包装为: |
| |
| ```JSON |
| { |
| "cteQueries": [ |
| { |
| "name": "cte1", |
| "plan": { |
| "name": "OutputNode-<id>", |
| "id": "<id>" |
| } |
| } |
| ], |
| "mainQuery": { |
| "name": "OutputNode-<id>", |
| "id": "<id>" |
| } |
| } |
| ``` |
| |
| 其中 `cteQueries[].plan` 与 `mainQuery` 均为 plan node JSON object。该结构用于同时保留 CTE 子查询计划与主查询计划。 |
| |
| 以[示例数据](../Reference/Sample-Data.md)中的 `table1` 为例: |
| |
| ```SQL |
| EXPLAIN (FORMAT JSON) SELECT * FROM table1; |
| ``` |
| |
| ```JSON |
| +-----------------+ |
| |distribution plan| |
| +-----------------+ |
| { |
| "name": "OutputNode-4", |
| "id": "4", |
| "properties": { |
| "OutputColumns": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ] |
| }, |
| "children": [ |
| { |
| "name": "CollectNode-33", |
| "id": "33", |
| "children": [ |
| { |
| "name": "ExchangeNode-40", |
| "id": "40", |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-32", |
| "id": "32", |
| "properties": { |
| "QualifiedTableName": "database1.table1", |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "DeviceNumber": "4", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "false", |
| "RegionId": "1" |
| } |
| } |
| ] |
| }, |
| { |
| "name": "ExchangeNode-41", |
| "id": "41", |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-31", |
| "id": "31", |
| "properties": { |
| "QualifiedTableName": "database1.table1", |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "DeviceNumber": "2", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "false", |
| "RegionId": "2" |
| } |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| } |
| +-----------------+ |
| ``` |
| |
| ## 3. EXPLAIN ANALYZE |
| |
| ### 3.1 语法 |
| |
| `EXPLAIN ANALYZE` 是 IoTDB 查询引擎自带的性能分析 SQL。与 `EXPLAIN` 不同,它会真实执行对应查询计划并统计执行信息,可用于追踪一条查询的具体性能分布,辅助资源观察、性能调优和异常分析。 |
| |
| ```SQL |
| EXPLAIN ANALYZE [VERBOSE] [(FORMAT { TEXT | JSON })] <SELECT_STATEMENT> |
| ``` |
| |
| 其中: |
| |
| |参数|说明| |
| |---|---| |
| |`SELECT_STATEMENT`|需要分析的查询语句| |
| |`VERBOSE`|打印更详细的分析结果。不填写时会省略部分细粒度统计| |
| |`FORMAT TEXT`|以默认文本形式输出分析结果,适合人工阅读| |
| |`FORMAT JSON`|以 JSON 对象输出分析结果,适合程序解析(自 V2.0.11 起支持)| |
| |
| ### 3.2 默认 TEXT 格式 |
| |
| `EXPLAIN ANALYZE` 默认格式为 `TEXT`,执行后将得到 `Explain Analyze` 结果列。结果由查询规划统计、fragment instance 统计、数据读取统计和算子树统计组成。 |
| |
| - **查询规划统计** |
| |
| `QueryStatistics` 包含查询层面的统计信息: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`Analyze Cost`|查询规划统计|SQL 分析阶段的耗时| |
| |`Fetch Partition Cost`|查询规划统计|拉取分区表的耗时| |
| |`Fetch Schema Cost`|查询规划统计|拉取元数据以及权限校验的耗时| |
| |`Logical Plan Cost`|查询规划统计|构建逻辑计划的耗时| |
| |`Logical Optimization Cost`|查询规划统计|逻辑计划优化的耗时| |
| |`Distribution Plan Cost`|查询规划统计|构建分布式计划的耗时| |
| |`Dispatch Cost`|查询规划统计|分发 fragment instance 的耗时| |
| |`Fragment Instances Count`|查询规划统计|总查询分片数量,每个查询分片的信息会依次输出| |
| |
| - **Fragment instance 统计** |
| |
| `FragmentInstance` 是 IoTDB 一个查询分片的封装。每个查询分片都会输出一份执行信息,主要包含 fragment 统计和算子信息。 |
| |
| fragment 统计包括: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`Total Wall Time`|fragment 统计|该分片从开始执行到执行结束的物理时间| |
| |`Cost of initDataQuerySource`|fragment 统计|构建查询文件列表的耗时| |
| |`Seq File(unclosed)`|fragment 统计|未封口的顺序文件数量| |
| |`Seq File(closed)`|fragment 统计|已封口的顺序文件数量| |
| |`UnSeq File(unclosed)`|fragment 统计|未封口的乱序文件数量| |
| |`UnSeq File(closed)`|fragment 统计|已封口的乱序文件数量| |
| |`ready queued time`|fragment 统计|查询分片所有 task 在 ready queue 中的总时长| |
| |`blocked queued time`|fragment 统计|查询分片所有 task 在 blocked queue 中的总时长| |
| |
| - **数据读取统计** |
| |
| `Query Statistics` 明细字段包括: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`loadBloomFilterFromCacheCount`|BloomFilter|命中 BloomFilterCache 的次数| |
| |`loadBloomFilterFromDiskCount`|BloomFilter|从磁盘读取 BloomFilter 的次数| |
| |`loadBloomFilterActualIOSize`|BloomFilter|从磁盘读取 BloomFilter 时产生的磁盘 IO,单位为 bytes| |
| |`loadBloomFilterTime`|BloomFilter|读取 BloomFilter 并计算序列是否存在的总耗时,单位为 ms| |
| |`loadTimeSeriesMetadataDiskSeqCount`|TimeSeriesMetadata|从已封口顺序文件中加载的 TimeSeriesMetadata 数量| |
| |`loadTimeSeriesMetadataDiskUnSeqCount`|TimeSeriesMetadata|从已封口乱序文件中加载的 TimeSeriesMetadata 数量| |
| |`loadTimeSeriesMetadataDiskSeqTime`|TimeSeriesMetadata|从已封口顺序文件中加载 TimeSeriesMetadata 的耗时| |
| |`loadTimeSeriesMetadataDiskUnSeqTime`|TimeSeriesMetadata|从已封口乱序文件中加载 TimeSeriesMetadata 的耗时| |
| |`loadTimeSeriesMetadataFromCacheCount`|TimeSeriesMetadata|命中 TimeSeriesMetadataCache 的次数| |
| |`loadTimeSeriesMetadataFromDiskCount`|TimeSeriesMetadata|从磁盘读取 TimeSeriesMetadata 的次数| |
| |`loadTimeSeriesMetadataActualIOSize`|TimeSeriesMetadata|从磁盘读取 TimeSeriesMetadata 时产生的磁盘 IO,单位为 bytes| |
| |`TimeSeriesMetadataModificationTime`|Mods 文件|读取 mods 文件的耗时| |
| |`constructAlignedChunkReadersDiskCount`|Chunk|构造 ChunkReader 的次数| |
| |`constructAlignedChunkReadersDiskTime`|Chunk|构造 ChunkReader 的总耗时,包含磁盘 IO 和解压缩| |
| |`pageReadersDecodeAlignedDiskCount`|Chunk|解码 page 的数量| |
| |`pageReadersDecodeAlignedDiskTime`|Chunk|解码 page 的总耗时| |
| |`loadChunkFromCacheCount`|Chunk|命中 ChunkCache 的次数| |
| |`loadChunkFromDiskCount`|Chunk|从磁盘读取 Chunk 的次数| |
| |`loadChunkActualIOSize`|Chunk|从磁盘读取 Chunk 时产生的磁盘 IO,单位为 bytes| |
| |
| - **算子树统计** |
| |
| 算子树统计包括: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`CPU Time`|算子树统计|当前算子的 CPU 执行耗时| |
| |`output`|算子树统计|当前算子的输出行数| |
| |`HasNext() Called Count`|算子树统计|当前算子 `HasNext()` 接口被调用的次数| |
| |`Next() Called Count`|算子树统计|当前算子 `Next()` 接口被调用的次数| |
| |`Estimated Memory Size`|算子树统计|当前算子的估算内存占用| |
| |节点专属统计信息|算子树统计|不同算子输出的定制统计字段,例如 `DeviceNumber`、`CurrentDeviceIndex`、`OutputPlanNodeId`、`size_in_bytes` 等| |
| |
| 常见节点专属统计字段包括: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`DeviceNumber`|`TableScan` 相关节点|当前 table scan 涉及的设备数量| |
| |`CurrentDeviceIndex`|`TableScan` 相关节点|当前正在扫描的设备索引| |
| |`OutputPlanNodeId`|sink 节点|sink 节点对应的下游接收数据节点| |
| |`size_in_bytes`|exchange 节点|exchange 节点接收到的 TsBlock 字节数,仅计算数据占用大小| |
| |`TimeSeriesIndexFilteredRows`|filter 下推到 table scan 时的 table scan 节点|通过序列元数据过滤掉的数据行数| |
| |`ChunkIndexFilteredRows`|filter 下推到 table scan 时的 table scan 节点|通过列块元数据过滤掉的数据行数| |
| |`PageIndexFilteredRows`|filter 下推到 table scan 时的 table scan 节点|通过页头内部统计信息过滤掉的数据行数| |
| |`RowScanFilteredRows`|filter 下推到 table scan 且使用 `VERBOSE` 时的 table scan 节点|逐行检查数据时被过滤掉的行数| |
| |
| 实际输出字段会随查询类型、涉及的算子、是否使用 `VERBOSE` 以及是否触发过滤下推而变化。未触发对应逻辑时,相关字段可能不会出现在结果中。 |
| |
| - **文本输出示例** |
| |
| 以[示例数据](../Reference/Sample-Data.md)中的 `table1` 为例,以下两条语句等价: |
| |
| ```SQL |
| EXPLAIN ANALYZE SELECT * FROM table1; |
| EXPLAIN ANALYZE (FORMAT TEXT) SELECT * FROM table1; |
| ``` |
| |
| ```SQL |
| +-------------------------------------------------------------------------------------------------------------------------+ |
| | Explain Analyze| |
| +-------------------------------------------------------------------------------------------------------------------------+ |
| |Analyze Cost: 3.862 ms | |
| |Fetch Partition Cost: 0.785 ms | |
| |Fetch Schema Cost: 5.473 ms | |
| |Logical Plan Cost: 37.350 ms | |
| |Logical Optimization Cost: 4.340 ms | |
| |Distribution Plan Cost: 1.287 ms | |
| |Dispatch Cost: 8.711 ms | |
| |Fragment Instances Count: 3 | |
| | | |
| |FRAGMENT-INSTANCE[Id: 20260722_064147_00096_1.2.0][IP: 127.0.0.1:10730][DataRegion: virtual_data_region][State: FINISHED]| |
| | Total Wall Time: 64 ms | |
| | Cost of initDataQuerySource: 0.000 ms | |
| | Seq File(unclosed): 0, Seq File(closed): 0 | |
| | UnSeq File(unclosed): 0, UnSeq File(closed): 0 | |
| | ready queued time: 0.428 ms, blocked queued time: 11.410 ms | |
| | Query Statistics: | |
| | timeSeriesIndexFilteredRows: 0 | |
| | chunkIndexFilteredRows: 0 | |
| | pageIndexFilteredRows: 0 | |
| | [PlanNodeId 69]: IdentitySinkNode(IdentitySinkOperator) | |
| | CPU Time: 28.691 ms | |
| | output: 18 rows | |
| | HasNext() Called Count: 9 | |
| | Next() Called Count: 8 | |
| | Estimated Memory Size: 131072 | |
| | DownStreamPlanNodeId: 66 | |
| | [PlanNodeId 55]: CollectNode(CollectOperator) | |
| | CPU Time: 28.656 ms | |
| | output: 18 rows | |
| | HasNext() Called Count: 9 | |
| | Next() Called Count: 8 | |
| | Estimated Memory Size: 131072 | |
| | [PlanNodeId 64]: ExchangeNode(ExchangeOperator) | |
| | CPU Time: 13.310 ms | |
| | output: 12 rows | |
| | HasNext() Called Count: 5 | |
| | Next() Called Count: 4 | |
| | Estimated Memory Size: 131072 | |
| | size_in_bytes: 3264 | |
| | [PlanNodeId 65]: ExchangeNode(ExchangeOperator) | |
| | CPU Time: 15.286 ms | |
| | output: 6 rows | |
| | HasNext() Called Count: 3 | |
| | Next() Called Count: 2 | |
| | Estimated Memory Size: 131072 | |
| | size_in_bytes: 1632 | |
| | | |
| |FRAGMENT-INSTANCE[Id: 20260722_064147_00096_1.3.0][IP: 127.0.0.1:10730][DataRegion: 1][State: FINISHED] | |
| | Total Wall Time: 32 ms | |
| | Cost of initDataQuerySource: 7.652 ms | |
| | Seq File(unclosed): 0, Seq File(closed): 0 | |
| | UnSeq File(unclosed): 2, UnSeq File(closed): 0 | |
| | ready queued time: 0.089 ms, blocked queued time: 0.000 ms | |
| | Query Statistics: | |
| | timeSeriesIndexFilteredRows: 0 | |
| | chunkIndexFilteredRows: 0 | |
| | pageIndexFilteredRows: 0 | |
| | [PlanNodeId 67]: IdentitySinkNode(IdentitySinkOperator) | |
| | CPU Time: 2.007 ms | |
| | output: 12 rows | |
| | HasNext() Called Count: 9 | |
| | Next() Called Count: 8 | |
| | Estimated Memory Size: 327680 | |
| | DownStreamPlanNodeId: 64 | |
| | [PlanNodeId 54]: DeviceTableScanNode(TableScanOperator) | |
| | CPU Time: 1.981 ms | |
| | output: 12 rows | |
| | HasNext() Called Count: 9 | |
| | Next() Called Count: 8 | |
| | Estimated Memory Size: 327680 | |
| | DeviceNumber: 4 | |
| | CurrentDeviceIndex: 3 | |
| | | |
| |FRAGMENT-INSTANCE[Id: 20260722_064147_00096_1.4.0][IP: 127.0.0.1:10730][DataRegion: 2][State: FINISHED] | |
| | Total Wall Time: 48 ms | |
| | Cost of initDataQuerySource: 0.933 ms | |
| | Seq File(unclosed): 0, Seq File(closed): 0 | |
| | UnSeq File(unclosed): 1, UnSeq File(closed): 0 | |
| | ready queued time: 0.141 ms, blocked queued time: 0.000 ms | |
| | Query Statistics: | |
| | timeSeriesIndexFilteredRows: 0 | |
| | chunkIndexFilteredRows: 0 | |
| | pageIndexFilteredRows: 0 | |
| | [PlanNodeId 68]: IdentitySinkNode(IdentitySinkOperator) | |
| | CPU Time: 1.846 ms | |
| | output: 6 rows | |
| | HasNext() Called Count: 5 | |
| | Next() Called Count: 4 | |
| | Estimated Memory Size: 327680 | |
| | DownStreamPlanNodeId: 65 | |
| | [PlanNodeId 53]: DeviceTableScanNode(TableScanOperator) | |
| | CPU Time: 1.755 ms | |
| | output: 6 rows | |
| | HasNext() Called Count: 5 | |
| | Next() Called Count: 4 | |
| | Estimated Memory Size: 327680 | |
| | DeviceNumber: 2 | |
| | CurrentDeviceIndex: 1 | |
| +-------------------------------------------------------------------------------------------------------------------------+ |
| ``` |
| |
| - **VERBOSE 输出示例** |
| |
| 使用 `VERBOSE` 可以查看更细粒度的数据读取和过滤统计: |
| |
| ```SQL |
| EXPLAIN ANALYZE VERBOSE SELECT * FROM table1; |
| EXPLAIN ANALYZE VERBOSE (FORMAT TEXT) SELECT * FROM table1; |
| ``` |
| |
| ```YAML |
| +-------------------------------------------------------------------------------------------------------------------------+ |
| | Explain Analyze| |
| +-------------------------------------------------------------------------------------------------------------------------+ |
| |Analyze Cost: 1.016 ms | |
| |Fetch Partition Cost: 0.555 ms | |
| |Fetch Schema Cost: 3.789 ms | |
| |Logical Plan Cost: 0.491 ms | |
| |Logical Optimization Cost: 2.625 ms | |
| |Distribution Plan Cost: 0.393 ms | |
| |Dispatch Cost: 37.041 ms | |
| |Fragment Instances Count: 3 | |
| | | |
| |FRAGMENT-INSTANCE[Id: 20260722_064913_00105_1.2.0][IP: 127.0.0.1:10730][DataRegion: virtual_data_region][State: FINISHED]| |
| | Total Wall Time: 43 ms | |
| | Cost of initDataQuerySource: 0.000 ms | |
| | Seq File(unclosed): 0, Seq File(closed): 0 | |
| | UnSeq File(unclosed): 0, UnSeq File(closed): 0 | |
| | ready queued time: 0.248 ms, blocked queued time: 23.757 ms | |
| | Query Statistics: | |
| | loadBloomFilterFromCacheCount: 0 | |
| | loadBloomFilterFromDiskCount: 0 | |
| | loadBloomFilterActualIOSize: 0 | |
| | loadBloomFilterTime: 0.000 | |
| | loadTimeSeriesMetadataFromCacheCount: 0 | |
| | loadTimeSeriesMetadataFromDiskCount: 0 | |
| | loadTimeSeriesMetadataActualIOSize: 0 | |
| | loadChunkFromCacheCount: 0 | |
| | loadChunkFromDiskCount: 0 | |
| | loadChunkActualIOSize: 0 | |
| | timeSeriesIndexFilteredRows: 0 | |
| | chunkIndexFilteredRows: 0 | |
| | pageIndexFilteredRows: 0 | |
| | rowScanFilteredRows: 0 | |
| | [PlanNodeId 69]: IdentitySinkNode(IdentitySinkOperator) | |
| | CPU Time: 0.988 ms | |
| | output: 18 rows | |
| | HasNext() Called Count: 9 | |
| | Next() Called Count: 8 | |
| | Estimated Memory Size: 131072 | |
| | DownStreamPlanNodeId: 66 | |
| | [PlanNodeId 55]: CollectNode(CollectOperator) | |
| | CPU Time: 0.954 ms | |
| | output: 18 rows | |
| | HasNext() Called Count: 9 | |
| | Next() Called Count: 8 | |
| | Estimated Memory Size: 131072 | |
| | [PlanNodeId 64]: ExchangeNode(ExchangeOperator) | |
| | CPU Time: 0.569 ms | |
| | output: 12 rows | |
| | HasNext() Called Count: 5 | |
| | Next() Called Count: 4 | |
| | Estimated Memory Size: 131072 | |
| | size_in_bytes: 3264 | |
| | [PlanNodeId 65]: ExchangeNode(ExchangeOperator) | |
| | CPU Time: 0.354 ms | |
| | output: 6 rows | |
| | HasNext() Called Count: 3 | |
| | Next() Called Count: 2 | |
| | Estimated Memory Size: 131072 | |
| | size_in_bytes: 1632 | |
| | | |
| |FRAGMENT-INSTANCE[Id: 20260722_064913_00105_1.3.0][IP: 127.0.0.1:10730][DataRegion: 1][State: FINISHED] | |
| | Total Wall Time: 32 ms | |
| | Cost of initDataQuerySource: 0.224 ms | |
| | Seq File(unclosed): 0, Seq File(closed): 2 | |
| | UnSeq File(unclosed): 0, UnSeq File(closed): 0 | |
| | ready queued time: 0.025 ms, blocked queued time: 0.000 ms | |
| | Query Statistics: | |
| | loadBloomFilterFromCacheCount: 2 | |
| | loadBloomFilterFromDiskCount: 0 | |
| | loadBloomFilterActualIOSize: 0 | |
| | loadBloomFilterTime: 0.018 | |
| | loadTimeSeriesMetadataAlignedDiskSeqCount: 4 | |
| | loadTimeSeriesMetadataAlignedDiskSeqTime: 0.189 | |
| | loadTimeSeriesMetadataFromCacheCount: 18 | |
| | loadTimeSeriesMetadataFromDiskCount: 2 | |
| | loadTimeSeriesMetadataActualIOSize: 0 | |
| | alignedTimeSeriesMetadataModificationTime: 0.026 | |
| | constructAlignedChunkReadersDiskCount: 4 | |
| | constructAlignedChunkReadersDiskTime: 3.251 | |
| | loadChunkFromCacheCount: 18 | |
| | loadChunkFromDiskCount: 0 | |
| | loadChunkActualIOSize: 0 | |
| | pageReadersDecodeAlignedDiskCount: 4 | |
| | pageReadersDecodeAlignedDiskTime: 0.210 | |
| | timeSeriesIndexFilteredRows: 0 | |
| | chunkIndexFilteredRows: 0 | |
| | pageIndexFilteredRows: 0 | |
| | rowScanFilteredRows: 0 | |
| | [PlanNodeId 67]: IdentitySinkNode(IdentitySinkOperator) | |
| | CPU Time: 5.150 ms | |
| | output: 12 rows | |
| | HasNext() Called Count: 9 | |
| | Next() Called Count: 8 | |
| | Estimated Memory Size: 327680 | |
| | DownStreamPlanNodeId: 64 | |
| | [PlanNodeId 54]: DeviceTableScanNode(TableScanOperator) | |
| | CPU Time: 5.136 ms | |
| | output: 12 rows | |
| | HasNext() Called Count: 9 | |
| | Next() Called Count: 8 | |
| | Estimated Memory Size: 327680 | |
| | DeviceNumber: 4 | |
| | CurrentDeviceIndex: 3 | |
| | | |
| |FRAGMENT-INSTANCE[Id: 20260722_064913_00105_1.4.0][IP: 127.0.0.1:10730][DataRegion: 2][State: FINISHED] | |
| | Total Wall Time: 32 ms | |
| | Cost of initDataQuerySource: 0.397 ms | |
| | Seq File(unclosed): 0, Seq File(closed): 1 | |
| | UnSeq File(unclosed): 0, UnSeq File(closed): 0 | |
| | ready queued time: 0.075 ms, blocked queued time: 0.000 ms | |
| | Query Statistics: | |
| | loadBloomFilterFromCacheCount: 0 | |
| | loadBloomFilterFromDiskCount: 0 | |
| | loadBloomFilterActualIOSize: 0 | |
| | loadBloomFilterTime: 0.000 | |
| | loadTimeSeriesMetadataAlignedDiskSeqCount: 2 | |
| | loadTimeSeriesMetadataAlignedDiskSeqTime: 0.313 | |
| | loadTimeSeriesMetadataFromCacheCount: 10 | |
| | loadTimeSeriesMetadataFromDiskCount: 0 | |
| | loadTimeSeriesMetadataActualIOSize: 0 | |
| | alignedTimeSeriesMetadataModificationTime: 0.046 | |
| | constructAlignedChunkReadersDiskCount: 2 | |
| | constructAlignedChunkReadersDiskTime: 2.307 | |
| | loadChunkFromCacheCount: 10 | |
| | loadChunkFromDiskCount: 0 | |
| | loadChunkActualIOSize: 0 | |
| | pageReadersDecodeAlignedDiskCount: 2 | |
| | pageReadersDecodeAlignedDiskTime: 0.129 | |
| | timeSeriesIndexFilteredRows: 0 | |
| | chunkIndexFilteredRows: 0 | |
| | pageIndexFilteredRows: 0 | |
| | rowScanFilteredRows: 0 | |
| | [PlanNodeId 68]: IdentitySinkNode(IdentitySinkOperator) | |
| | CPU Time: 4.187 ms | |
| | output: 6 rows | |
| | HasNext() Called Count: 5 | |
| | Next() Called Count: 4 | |
| | Estimated Memory Size: 327680 | |
| | DownStreamPlanNodeId: 65 | |
| | [PlanNodeId 53]: DeviceTableScanNode(TableScanOperator) | |
| | CPU Time: 4.172 ms | |
| | output: 6 rows | |
| | HasNext() Called Count: 5 | |
| | Next() Called Count: 4 | |
| | Estimated Memory Size: 327680 | |
| | DeviceNumber: 2 | |
| | CurrentDeviceIndex: 1 | |
| +-------------------------------------------------------------------------------------------------------------------------+ |
| ``` |
| |
| ### 3.3 JSON 格式 |
| |
| 使用 `EXPLAIN ANALYZE (FORMAT JSON)` 可以返回计划阶段耗时、fragment instance 统计、operator 统计等结构化信息。JSON 格式自 V2.0.11 起支持。 |
| |
| #### 3.3.1 默认 JSON 输出 |
| |
| ```SQL |
| EXPLAIN ANALYZE (FORMAT JSON) SELECT * FROM t1; |
| ``` |
| |
| 顶层 JSON 结构如下: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`planStatistics`|object|查询分析、分区获取、schema 获取、逻辑规划、逻辑优化、分布式规划、dispatch 等阶段耗时| |
| |`fragmentInstancesCount`|number|返回统计信息的 fragment instance 数量| |
| |`fragmentInstances`|array|各 fragment instance 的执行统计| |
| |
| `planStatistics` 主要字段如下: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`analyzeCostMs`|planStatistics|SQL 分析耗时,单位 ms| |
| |`fetchPartitionCostMs`|planStatistics|获取分区信息耗时,单位 ms| |
| |`fetchSchemaCostMs`|planStatistics|获取 schema 信息耗时,单位 ms| |
| |`logicalPlanCostMs`|planStatistics|逻辑计划生成耗时,单位 ms| |
| |`logicalOptimizationCostMs`|planStatistics|逻辑优化耗时,单位 ms| |
| |`distributionPlanCostMs`|planStatistics|分布式计划生成耗时,单位 ms| |
| |`dispatchCostMs`|planStatistics|fragment dispatch 耗时,单位 ms| |
| |
| `fragmentInstances[]` 主要字段如下: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`id`|fragmentInstances[]|fragment instance id| |
| |`ip`|fragmentInstances[]|执行该 fragment instance 的节点 IP| |
| |`dataRegion`|fragmentInstances[]|对应 DataRegion| |
| |`state`|fragmentInstances[]|fragment instance 最终状态| |
| |`totalWallTimeMs`|fragmentInstances[]|总 wall time,单位 ms| |
| |`initDataQuerySourceCostMs`|fragmentInstances[]|初始化数据源耗时,单位 ms| |
| |`initDataQuerySourceRetryCount`|fragmentInstances[]|初始化数据源重试次数。仅当大于 0 时输出| |
| |`seqFileUnclosed`、`seqFileClosed`、`unseqFileUnclosed`、`unseqFileClosed`|fragmentInstances[]|涉及的顺序和乱序文件数量| |
| |`readyQueuedTimeMs`、`blockQueuedTimeMs`|fragmentInstances[]|ready / block 队列等待时间,单位 ms| |
| |`queryStatistics`|fragmentInstances[]|扫描、过滤、chunk/page reader 等查询统计| |
| |`operators`|fragmentInstances[]|operator tree 及每个 operator 的执行统计| |
| |
| `operators` 为与 plan tree 对应的树状结构,主要字段如下: |
| |
| |字段|类型/出现位置|说明| |
| |---|---|---| |
| |`planNodeId`|operators|对应 plan node id| |
| |`nodeType`|operators|plan node 类型| |
| |`operatorType`|operators|实际执行 operator 类型| |
| |`count`|operators|operator 统计聚合次数。仅当存在时输出| |
| |`cpuTimeMs`|operators|operator CPU 执行耗时,单位 ms| |
| |`outputRows`|operators|输出行数| |
| |`hasNextCalledCount`、`nextCalledCount`|operators|operator 迭代调用次数| |
| |`estimatedMemorySize`|operators|估算内存占用。仅非 0 时输出| |
| |`specifiedInfo`|operators|operator 特有统计信息。仅非空时输出| |
| |`children`|operators|子 operator 数组| |
| |
| 以[示例数据](../Reference/Sample-Data.md)中的 `table1` 为例: |
| |
| ```SQL |
| EXPLAIN ANALYZE (FORMAT JSON) SELECT * FROM table1; |
| ``` |
| |
| ```JSON |
| +---------------+ |
| |Explain Analyze| |
| +---------------+ |
| { |
| "planStatistics": { |
| "analyzeCostMs": 4.948, |
| "fetchPartitionCostMs": 2.104, |
| "fetchSchemaCostMs": 13.321, |
| "logicalPlanCostMs": 2.264, |
| "logicalOptimizationCostMs": 7.941, |
| "distributionPlanCostMs": 1.434, |
| "dispatchCostMs": 9.023 |
| }, |
| "fragmentInstancesCount": 3, |
| "fragmentInstances": [ |
| { |
| "id": "20260722_064302_00101_1.2.0", |
| "ip": "127.0.0.1:10730", |
| "dataRegion": "virtual_data_region", |
| "state": "FINISHED", |
| "totalWallTimeMs": 97, |
| "initDataQuerySourceCostMs": 0.0, |
| "seqFileUnclosed": 0, |
| "seqFileClosed": 0, |
| "unseqFileUnclosed": 0, |
| "unseqFileClosed": 0, |
| "readyQueuedTimeMs": 0.858, |
| "blockQueuedTimeMs": 71.752, |
| "queryStatistics": { |
| "timeSeriesIndexFilteredRows": 0, |
| "chunkIndexFilteredRows": 0, |
| "pageIndexFilteredRows": 0 |
| }, |
| "operators": { |
| "planNodeId": "69", |
| "nodeType": "IdentitySinkNode", |
| "operatorType": "IdentitySinkOperator", |
| "cpuTimeMs": 6.082, |
| "outputRows": 18, |
| "hasNextCalledCount": 9, |
| "nextCalledCount": 8, |
| "estimatedMemorySize": 131072, |
| "specifiedInfo": { |
| "DownStreamPlanNodeId": "66" |
| }, |
| "children": [ |
| { |
| "planNodeId": "55", |
| "nodeType": "CollectNode", |
| "operatorType": "CollectOperator", |
| "cpuTimeMs": 6.065, |
| "outputRows": 18, |
| "hasNextCalledCount": 9, |
| "nextCalledCount": 8, |
| "estimatedMemorySize": 131072, |
| "children": [ |
| { |
| "planNodeId": "64", |
| "nodeType": "ExchangeNode", |
| "operatorType": "ExchangeOperator", |
| "cpuTimeMs": 1.119, |
| "outputRows": 12, |
| "hasNextCalledCount": 5, |
| "nextCalledCount": 4, |
| "estimatedMemorySize": 131072, |
| "specifiedInfo": { |
| "size_in_bytes": "3264" |
| } |
| }, |
| { |
| "planNodeId": "65", |
| "nodeType": "ExchangeNode", |
| "operatorType": "ExchangeOperator", |
| "cpuTimeMs": 4.909, |
| "outputRows": 6, |
| "hasNextCalledCount": 3, |
| "nextCalledCount": 2, |
| "estimatedMemorySize": 131072, |
| "specifiedInfo": { |
| "size_in_bytes": "1632" |
| } |
| } |
| ] |
| } |
| ] |
| } |
| }, |
| { |
| "id": "20260722_064302_00101_1.3.0", |
| "ip": "127.0.0.1:10730", |
| "dataRegion": "1", |
| "state": "FINISHED", |
| "totalWallTimeMs": 63, |
| "initDataQuerySourceCostMs": 0.338, |
| "seqFileUnclosed": 0, |
| "seqFileClosed": 2, |
| "unseqFileUnclosed": 0, |
| "unseqFileClosed": 0, |
| "readyQueuedTimeMs": 0.273, |
| "blockQueuedTimeMs": 0.0, |
| "queryStatistics": { |
| "timeSeriesIndexFilteredRows": 0, |
| "chunkIndexFilteredRows": 0, |
| "pageIndexFilteredRows": 0 |
| }, |
| "operators": { |
| "planNodeId": "67", |
| "nodeType": "IdentitySinkNode", |
| "operatorType": "IdentitySinkOperator", |
| "cpuTimeMs": 57.338, |
| "outputRows": 12, |
| "hasNextCalledCount": 9, |
| "nextCalledCount": 8, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DownStreamPlanNodeId": "64" |
| }, |
| "children": [ |
| { |
| "planNodeId": "54", |
| "nodeType": "DeviceTableScanNode", |
| "operatorType": "TableScanOperator", |
| "cpuTimeMs": 57.248, |
| "outputRows": 12, |
| "hasNextCalledCount": 9, |
| "nextCalledCount": 8, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DeviceNumber": "4", |
| "CurrentDeviceIndex": "3" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "id": "20260722_064302_00101_1.4.0", |
| "ip": "127.0.0.1:10730", |
| "dataRegion": "2", |
| "state": "FINISHED", |
| "totalWallTimeMs": 79, |
| "initDataQuerySourceCostMs": 0.231, |
| "seqFileUnclosed": 0, |
| "seqFileClosed": 1, |
| "unseqFileUnclosed": 0, |
| "unseqFileClosed": 0, |
| "readyQueuedTimeMs": 0.038, |
| "blockQueuedTimeMs": 0.0, |
| "queryStatistics": { |
| "timeSeriesIndexFilteredRows": 0, |
| "chunkIndexFilteredRows": 0, |
| "pageIndexFilteredRows": 0 |
| }, |
| "operators": { |
| "planNodeId": "68", |
| "nodeType": "IdentitySinkNode", |
| "operatorType": "IdentitySinkOperator", |
| "cpuTimeMs": 66.387, |
| "outputRows": 6, |
| "hasNextCalledCount": 5, |
| "nextCalledCount": 4, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DownStreamPlanNodeId": "65" |
| }, |
| "children": [ |
| { |
| "planNodeId": "53", |
| "nodeType": "DeviceTableScanNode", |
| "operatorType": "TableScanOperator", |
| "cpuTimeMs": 66.362, |
| "outputRows": 6, |
| "hasNextCalledCount": 5, |
| "nextCalledCount": 4, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DeviceNumber": "2", |
| "CurrentDeviceIndex": "1" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| +---------------+ |
| ``` |
| |
| #### 3.3.2 VERBOSE JSON 输出 |
| |
| 当使用 `EXPLAIN ANALYZE VERBOSE (FORMAT JSON)` 时,顶层结构与非 verbose JSON 一致,但 `queryStatistics` 会在基础过滤行数外补充更细粒度统计,包括 bloom filter、time series metadata、chunk、page reader、modification 和实际 IO size 等信息。 |
| |
| `VERBOSE` 与非 `VERBOSE` JSON 输出的主要差异如下: |
| |
| |输出模式|顶层结构|`queryStatistics` 字段粒度|典型字段| |
| |---|---|---|---| |
| |`EXPLAIN ANALYZE (FORMAT JSON)`|`planStatistics`、`fragmentInstancesCount`、`fragmentInstances`|默认统计字段|`timeSeriesIndexFilteredRows`、`chunkIndexFilteredRows`、`pageIndexFilteredRows`| |
| |`EXPLAIN ANALYZE VERBOSE (FORMAT JSON)`|与非 `VERBOSE` 一致|更详细的扫描、读取和过滤统计|`loadBloomFilterFromCacheCount`、`loadTimeSeriesMetadataFromCacheCount`、`loadChunkFromDiskCount`、`pageReadersDecodeAlignedMemCount`、`rowScanFilteredRows`| |
| |
| 以[示例数据](../Reference/Sample-Data.md)中的 `table1` 为例: |
| |
| ```SQL |
| EXPLAIN ANALYZE VERBOSE (FORMAT JSON) SELECT * FROM table1; |
| ``` |
| |
| ```JSON |
| +---------------+ |
| |Explain Analyze| |
| +---------------+ |
| { |
| "planStatistics": { |
| "analyzeCostMs": 3.505, |
| "fetchPartitionCostMs": 2.003, |
| "fetchSchemaCostMs": 9.198, |
| "logicalPlanCostMs": 1.481, |
| "logicalOptimizationCostMs": 6.684, |
| "distributionPlanCostMs": 0.711, |
| "dispatchCostMs": 8.32 |
| }, |
| "fragmentInstancesCount": 3, |
| "fragmentInstances": [ |
| { |
| "id": "20260722_064502_00103_1.2.0", |
| "ip": "127.0.0.1:10730", |
| "dataRegion": "virtual_data_region", |
| "state": "FINISHED", |
| "totalWallTimeMs": 48, |
| "initDataQuerySourceCostMs": 0.0, |
| "seqFileUnclosed": 0, |
| "seqFileClosed": 0, |
| "unseqFileUnclosed": 0, |
| "unseqFileClosed": 0, |
| "readyQueuedTimeMs": 0.209, |
| "blockQueuedTimeMs": 17.997, |
| "queryStatistics": { |
| "loadBloomFilterFromCacheCount": 0, |
| "loadBloomFilterFromDiskCount": 0, |
| "loadBloomFilterActualIOSize": 0, |
| "loadBloomFilterTimeMs": 0.0, |
| "loadTimeSeriesMetadataFromCacheCount": 0, |
| "loadTimeSeriesMetadataFromDiskCount": 0, |
| "loadTimeSeriesMetadataActualIOSize": 0, |
| "loadChunkFromCacheCount": 0, |
| "loadChunkFromDiskCount": 0, |
| "loadChunkActualIOSize": 0, |
| "timeSeriesIndexFilteredRows": 0, |
| "chunkIndexFilteredRows": 0, |
| "pageIndexFilteredRows": 0, |
| "rowScanFilteredRows": 0 |
| }, |
| "operators": { |
| "planNodeId": "69", |
| "nodeType": "IdentitySinkNode", |
| "operatorType": "IdentitySinkOperator", |
| "cpuTimeMs": 26.368, |
| "outputRows": 18, |
| "hasNextCalledCount": 9, |
| "nextCalledCount": 8, |
| "estimatedMemorySize": 131072, |
| "specifiedInfo": { |
| "DownStreamPlanNodeId": "66" |
| }, |
| "children": [ |
| { |
| "planNodeId": "55", |
| "nodeType": "CollectNode", |
| "operatorType": "CollectOperator", |
| "cpuTimeMs": 26.32, |
| "outputRows": 18, |
| "hasNextCalledCount": 9, |
| "nextCalledCount": 8, |
| "estimatedMemorySize": 131072, |
| "children": [ |
| { |
| "planNodeId": "64", |
| "nodeType": "ExchangeNode", |
| "operatorType": "ExchangeOperator", |
| "cpuTimeMs": 0.47, |
| "outputRows": 12, |
| "hasNextCalledCount": 5, |
| "nextCalledCount": 4, |
| "estimatedMemorySize": 131072, |
| "specifiedInfo": { |
| "size_in_bytes": "3264" |
| } |
| }, |
| { |
| "planNodeId": "65", |
| "nodeType": "ExchangeNode", |
| "operatorType": "ExchangeOperator", |
| "cpuTimeMs": 25.802, |
| "outputRows": 6, |
| "hasNextCalledCount": 3, |
| "nextCalledCount": 2, |
| "estimatedMemorySize": 131072, |
| "specifiedInfo": { |
| "size_in_bytes": "1632" |
| } |
| } |
| ] |
| } |
| ] |
| } |
| }, |
| { |
| "id": "20260722_064502_00103_1.3.0", |
| "ip": "127.0.0.1:10730", |
| "dataRegion": "1", |
| "state": "FINISHED", |
| "totalWallTimeMs": 21, |
| "initDataQuerySourceCostMs": 0.232, |
| "seqFileUnclosed": 0, |
| "seqFileClosed": 2, |
| "unseqFileUnclosed": 0, |
| "unseqFileClosed": 0, |
| "readyQueuedTimeMs": 0.007, |
| "blockQueuedTimeMs": 0.0, |
| "queryStatistics": { |
| "loadBloomFilterFromCacheCount": 2, |
| "loadBloomFilterFromDiskCount": 0, |
| "loadBloomFilterActualIOSize": 0, |
| "loadBloomFilterTimeMs": 0.02, |
| "loadTimeSeriesMetadataAlignedDiskSeqCount": 4, |
| "loadTimeSeriesMetadataAlignedDiskSeqTimeMs": 0.483, |
| "loadTimeSeriesMetadataFromCacheCount": 18, |
| "loadTimeSeriesMetadataFromDiskCount": 2, |
| "loadTimeSeriesMetadataActualIOSize": 0, |
| "alignedTimeSeriesMetadataModificationTimeMs": 0.061, |
| "constructAlignedChunkReadersDiskCount": 4, |
| "constructAlignedChunkReadersDiskTimeMs": 2.693, |
| "loadChunkFromCacheCount": 18, |
| "loadChunkFromDiskCount": 0, |
| "loadChunkActualIOSize": 0, |
| "pageReadersDecodeAlignedDiskCount": 4, |
| "pageReadersDecodeAlignedDiskTimeMs": 0.22, |
| "timeSeriesIndexFilteredRows": 0, |
| "chunkIndexFilteredRows": 0, |
| "pageIndexFilteredRows": 0, |
| "rowScanFilteredRows": 0 |
| }, |
| "operators": { |
| "planNodeId": "67", |
| "nodeType": "IdentitySinkNode", |
| "operatorType": "IdentitySinkOperator", |
| "cpuTimeMs": 5.002, |
| "outputRows": 12, |
| "hasNextCalledCount": 9, |
| "nextCalledCount": 8, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DownStreamPlanNodeId": "64" |
| }, |
| "children": [ |
| { |
| "planNodeId": "54", |
| "nodeType": "DeviceTableScanNode", |
| "operatorType": "TableScanOperator", |
| "cpuTimeMs": 4.94, |
| "outputRows": 12, |
| "hasNextCalledCount": 9, |
| "nextCalledCount": 8, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DeviceNumber": "4", |
| "CurrentDeviceIndex": "3" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "id": "20260722_064502_00103_1.4.0", |
| "ip": "127.0.0.1:10730", |
| "dataRegion": "2", |
| "state": "FINISHED", |
| "totalWallTimeMs": 32, |
| "initDataQuerySourceCostMs": 0.253, |
| "seqFileUnclosed": 0, |
| "seqFileClosed": 1, |
| "unseqFileUnclosed": 0, |
| "unseqFileClosed": 0, |
| "readyQueuedTimeMs": 0.027, |
| "blockQueuedTimeMs": 0.0, |
| "queryStatistics": { |
| "loadBloomFilterFromCacheCount": 0, |
| "loadBloomFilterFromDiskCount": 0, |
| "loadBloomFilterActualIOSize": 0, |
| "loadBloomFilterTimeMs": 0.0, |
| "loadTimeSeriesMetadataAlignedDiskSeqCount": 2, |
| "loadTimeSeriesMetadataAlignedDiskSeqTimeMs": 0.188, |
| "loadTimeSeriesMetadataFromCacheCount": 10, |
| "loadTimeSeriesMetadataFromDiskCount": 0, |
| "loadTimeSeriesMetadataActualIOSize": 0, |
| "alignedTimeSeriesMetadataModificationTimeMs": 0.037, |
| "constructAlignedChunkReadersDiskCount": 2, |
| "constructAlignedChunkReadersDiskTimeMs": 1.807, |
| "loadChunkFromCacheCount": 10, |
| "loadChunkFromDiskCount": 0, |
| "loadChunkActualIOSize": 0, |
| "pageReadersDecodeAlignedDiskCount": 2, |
| "pageReadersDecodeAlignedDiskTimeMs": 0.62, |
| "timeSeriesIndexFilteredRows": 0, |
| "chunkIndexFilteredRows": 0, |
| "pageIndexFilteredRows": 0, |
| "rowScanFilteredRows": 0 |
| }, |
| "operators": { |
| "planNodeId": "68", |
| "nodeType": "IdentitySinkNode", |
| "operatorType": "IdentitySinkOperator", |
| "cpuTimeMs": 3.652, |
| "outputRows": 6, |
| "hasNextCalledCount": 5, |
| "nextCalledCount": 4, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DownStreamPlanNodeId": "65" |
| }, |
| "children": [ |
| { |
| "planNodeId": "53", |
| "nodeType": "DeviceTableScanNode", |
| "operatorType": "TableScanOperator", |
| "cpuTimeMs": 3.633, |
| "outputRows": 6, |
| "hasNextCalledCount": 5, |
| "nextCalledCount": 4, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DeviceNumber": "2", |
| "CurrentDeviceIndex": "1" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| ``` |
| |
| ## 4. 场景示例 |
| |
| ### 4.1 CTE 查询计划 |
| |
| 当 `EXPLAIN (FORMAT JSON)` 分析包含 materialized CTE 的查询时,输出会使用 `cteQueries` \+ `mainQuery` 的包装结构。 |
| |
| 以[示例数据](../Reference/Sample-Data.md)中的 `table1` 和 `table2` 为例: |
| |
| ```SQL |
| EXPLAIN (FORMAT JSON) |
| WITH cte1 AS MATERIALIZED (SELECT * FROM table2) |
| SELECT * FROM table1 |
| WHERE table1.device_id IN (SELECT device_id FROM cte1); |
| ``` |
| |
| ```JSON |
| +-----------------+ |
| |distribution plan| |
| +-----------------+ |
| { |
| "cteQueries": [ |
| { |
| "name": "cte1", |
| "plan": { |
| "name": "OutputNode-4", |
| "id": "4", |
| "properties": { |
| "OutputColumns": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ] |
| }, |
| "children": [ |
| { |
| "name": "CollectNode-33", |
| "id": "33", |
| "children": [ |
| { |
| "name": "ExchangeNode-40", |
| "id": "40", |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-32", |
| "id": "32", |
| "properties": { |
| "QualifiedTableName": "database1.table2", |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "DeviceNumber": "3", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "false", |
| "RegionId": "1" |
| } |
| } |
| ] |
| }, |
| { |
| "name": "ExchangeNode-41", |
| "id": "41", |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-31", |
| "id": "31", |
| "properties": { |
| "QualifiedTableName": "database1.table2", |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "DeviceNumber": "3", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "false", |
| "RegionId": "2" |
| } |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| } |
| } |
| ], |
| "mainQuery": { |
| "name": "OutputNode-12", |
| "id": "12", |
| "properties": { |
| "OutputColumns": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ] |
| }, |
| "children": [ |
| { |
| "name": "ProjectNode-35", |
| "id": "35", |
| "properties": { |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "Expressions": [ |
| "\"time\"", |
| "\"region\"", |
| "\"plant_id\"", |
| "\"device_id\"", |
| "\"model_id\"", |
| "\"maintenance\"", |
| "\"temperature\"", |
| "\"humidity\"", |
| "\"status\"", |
| "\"arrival_time\"" |
| ] |
| }, |
| "children": [ |
| { |
| "name": "FilterNode-138", |
| "id": "138", |
| "properties": { |
| "Predicate": "\"expr\"" |
| }, |
| "children": [ |
| { |
| "name": "SemiJoinNode-109", |
| "id": "109", |
| "children": [ |
| { |
| "name": "ExchangeNode-218", |
| "id": "218", |
| "children": [ |
| { |
| "name": "MergeSortNode-197", |
| "id": "197", |
| "properties": { |
| "OrderBy": "{orderBy\u003d[device_id], orderings\u003d{device_id\u003dASC NULLS LAST}}" |
| }, |
| "children": [ |
| { |
| "name": "ExchangeNode-216", |
| "id": "216", |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-196", |
| "id": "196", |
| "properties": { |
| "QualifiedTableName": "database1.table1", |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "DeviceNumber": "4", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "true", |
| "RegionId": "1" |
| } |
| } |
| ] |
| }, |
| { |
| "name": "ExchangeNode-217", |
| "id": "217", |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-195", |
| "id": "195", |
| "properties": { |
| "QualifiedTableName": "database1.table1", |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "DeviceNumber": "2", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "true", |
| "RegionId": "2" |
| } |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| }, |
| { |
| "name": "ExchangeNode-219", |
| "id": "219", |
| "children": [ |
| { |
| "name": "SortNode-137", |
| "id": "137", |
| "properties": { |
| "OrderBy": "{orderBy\u003d[device_id_3], orderings\u003d{device_id_3\u003dASC NULLS FIRST}}" |
| }, |
| "children": [ |
| { |
| "name": "ProjectNode-6", |
| "id": "6", |
| "properties": { |
| "OutputSymbols": [ |
| "device_id_3" |
| ], |
| "Expressions": [ |
| "\"device_id_3\"" |
| ] |
| }, |
| "children": [ |
| { |
| "name": "CteScanNode-2", |
| "id": "2" |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| } |
| } |
| +-----------------+ |
| ``` |
| |
| ### 4.2 Prepared Statement 与动态 SQL |
| |
| 通过 `EXECUTE` 或 `EXECUTE IMMEDIATE` 分析预处理语句和动态 SQL 时,指定的输出格式会在语句展开后继续生效,不会退回默认的 `GRAPHVIZ` 或 `TEXT` 格式。 |
| |
| ```SQL |
| PREPARE explain_json_stmt FROM SELECT * FROM table1 WHERE device_id = ?; |
| EXPLAIN (FORMAT JSON) EXECUTE explain_json_stmt USING '101'; |
| |
| EXPLAIN ANALYZE (FORMAT JSON) EXECUTE IMMEDIATE 'SELECT * FROM table1 WHERE device_id = ?' USING '101'; |
| ``` |
| |
| 其中: |
| |
| - `EXPLAIN (FORMAT JSON) EXECUTE ...` 返回 plan node JSON object。 |
| |
| - `EXPLAIN ANALYZE (FORMAT JSON) EXECUTE IMMEDIATE ...` 返回包含 `planStatistics`、`fragmentInstancesCount`、`fragmentInstances` 的 JSON object。 |
| |
| 1. `EXPLAIN (FORMAT JSON) EXECUTE ...` 输出结构示例: |
| |
| ```JSON |
| +-----------------+ |
| |distribution plan| |
| +-----------------+ |
| { |
| "name": "OutputNode-5", |
| "id": "5", |
| "properties": { |
| "OutputColumns": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ] |
| }, |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-46", |
| "id": "46", |
| "properties": { |
| "QualifiedTableName": "database1.table1", |
| "OutputSymbols": [ |
| "time", |
| "region", |
| "plant_id", |
| "device_id", |
| "model_id", |
| "maintenance", |
| "temperature", |
| "humidity", |
| "status", |
| "arrival_time" |
| ], |
| "DeviceNumber": "3", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "false", |
| "RegionId": "1" |
| } |
| } |
| ] |
| } |
| +-----------------+ |
| ``` |
| |
| 2. `EXPLAIN ANALYZE (FORMAT JSON) EXECUTE IMMEDIATE ...` 输出结构示例: |
| |
| ```JSON |
| +---------------+ |
| |Explain Analyze| |
| +---------------+ |
| { |
| "planStatistics": { |
| "analyzeCostMs": 2.904, |
| "fetchPartitionCostMs": 1.35, |
| "fetchSchemaCostMs": 5.259, |
| "logicalPlanCostMs": 1.123, |
| "logicalOptimizationCostMs": 6.157, |
| "distributionPlanCostMs": 0.571, |
| "dispatchCostMs": 5.909 |
| }, |
| "fragmentInstancesCount": 1, |
| "fragmentInstances": [ |
| { |
| "id": "20260722_065558_00118_1.2.0", |
| "ip": "127.0.0.1:10730", |
| "dataRegion": "1", |
| "state": "FINISHED", |
| "totalWallTimeMs": 10, |
| "initDataQuerySourceCostMs": 1.768, |
| "seqFileUnclosed": 0, |
| "seqFileClosed": 2, |
| "unseqFileUnclosed": 0, |
| "unseqFileClosed": 0, |
| "readyQueuedTimeMs": 0.059, |
| "blockQueuedTimeMs": 0.0, |
| "queryStatistics": { |
| "timeSeriesIndexFilteredRows": 0, |
| "chunkIndexFilteredRows": 0, |
| "pageIndexFilteredRows": 0 |
| }, |
| "operators": { |
| "planNodeId": "74", |
| "nodeType": "IdentitySinkNode", |
| "operatorType": "IdentitySinkOperator", |
| "cpuTimeMs": 9.193, |
| "outputRows": 10, |
| "hasNextCalledCount": 7, |
| "nextCalledCount": 6, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DownStreamPlanNodeId": "73" |
| }, |
| "children": [ |
| { |
| "planNodeId": "68", |
| "nodeType": "DeviceTableScanNode", |
| "operatorType": "TableScanOperator", |
| "cpuTimeMs": 9.055, |
| "outputRows": 10, |
| "hasNextCalledCount": 7, |
| "nextCalledCount": 6, |
| "estimatedMemorySize": 327680, |
| "specifiedInfo": { |
| "DeviceNumber": "3", |
| "CurrentDeviceIndex": "2" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| +---------------+ |
| ``` |
| |
| ### 4.3 CLI 中的 JSON 展示 |
| |
| CLI 对普通查询结果默认按表格输出。对于 JSON 格式的查询分析结果,如果继续把 JSON 正文放入表格单元格,每一行都会带上 `|` 边框,不利于复制、保存和 JSON 解析。 |
| |
| 当满足以下条件时,CLI 会切换为 raw JSON 展示: |
| |
| |条件|说明| |
| |---|---| |
| |结果集只有一列|避免影响普通多列查询展示| |
| |列名为 `distribution plan` 或 `Explain Analyze`|仅匹配 `EXPLAIN` / `EXPLAIN ANALYZE` 的结果列| |
| |首个结果值 trim 后以 `{` 或 `[` 开始|仅对 JSON object / array 内容启用 raw 输出| |
| |
| raw JSON 展示规则: |
| |
| - CLI 仍输出列名表头和外层分隔线,用户可以识别当前列为 `distribution plan` 或 `Explain Analyze`。 |
| |
| - JSON 正文逐行原样输出,不添加 `|` 表格边框。 |
| |
| - JSON 结束后输出分隔线和行数统计。 |
| |
| - 非 JSON 的 `EXPLAIN`、默认文本 `EXPLAIN ANALYZE`、普通查询结果仍走原有表格输出。 |
| |
| raw JSON 展示与普通表格输出的区别如下: |
| |
| |输出类型|适用结果|展示方式|复制与解析| |
| |---|---|---|---| |
| |普通表格输出|普通查询结果、默认 `EXPLAIN`、默认 `EXPLAIN ANALYZE`|每一行内容都放在表格边框内|适合人工查看,不适合直接作为 JSON 复制解析| |
| |raw JSON 输出|`EXPLAIN (FORMAT JSON)`、`EXPLAIN ANALYZE (FORMAT JSON)`|保留列名表头,JSON 正文不加表格边框|适合直接复制、保存或交给 JSON parser 解析| |
| |
| 示例: |
| |
| ```SQL |
| start-cli.sh -sql_dialect table -e "EXPLAIN (FORMAT JSON) SELECT time, device_id, temperature FROM database1.table1" |
| ``` |
| |
| ```SQL |
| +-----------------+ |
| |distribution plan| |
| +-----------------+ |
| { |
| "name": "OutputNode-4", |
| "id": "4", |
| "properties": { |
| "OutputColumns": [ |
| "time", |
| "device_id", |
| "temperature" |
| ], |
| "OutputSymbols": [ |
| "time", |
| "device_id", |
| "temperature" |
| ] |
| }, |
| "children": [ |
| { |
| "name": "CollectNode-42", |
| "id": "42", |
| "children": [ |
| { |
| "name": "ExchangeNode-49", |
| "id": "49", |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-41", |
| "id": "41", |
| "properties": { |
| "QualifiedTableName": "database1.table1", |
| "OutputSymbols": [ |
| "time", |
| "device_id", |
| "temperature" |
| ], |
| "DeviceNumber": "4", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "false", |
| "RegionId": "1" |
| } |
| } |
| ] |
| }, |
| { |
| "name": "ExchangeNode-50", |
| "id": "50", |
| "children": [ |
| { |
| "name": "DeviceTableScanNode-40", |
| "id": "40", |
| "properties": { |
| "QualifiedTableName": "database1.table1", |
| "OutputSymbols": [ |
| "time", |
| "device_id", |
| "temperature" |
| ], |
| "DeviceNumber": "2", |
| "ScanOrder": "ASC", |
| "PushDownOffset": "0", |
| "PushDownLimit": "0", |
| "PushDownLimitToEachDevice": "false", |
| "RegionId": "2" |
| } |
| } |
| ] |
| } |
| ] |
| } |
| ] |
| } |
| +-----------------+ |
| ``` |
| |
| ### 4.4 非法格式组合 |
| |
| `EXPLAIN` 和 `EXPLAIN ANALYZE` 支持的格式不同。非法格式组合会返回明确错误。 |
| |
| |语句|默认格式|支持格式|不支持格式| |
| |---|---|---|---| |
| |`EXPLAIN`|`GRAPHVIZ`|`GRAPHVIZ`、`JSON`|`TEXT`、`XML`、其他未知格式| |
| |`EXPLAIN ANALYZE`|`TEXT`|`TEXT`、`JSON`|`GRAPHVIZ`、`XML`、其他未知格式| |
| |
| 示例: |
| |
| ```SQL |
| EXPLAIN (FORMAT TEXT) SELECT * FROM table1; |
| EXPLAIN ANALYZE (FORMAT GRAPHVIZ) SELECT * FROM table1; |
| EXPLAIN (FORMAT XML) SELECT * FROM table1; |
| ``` |
| |
| 对应报错: |
| |
| ```SQL |
| Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 701: Invalid EXPLAIN format: TEXT. Supported formats: GRAPHVIZ, JSON |
| Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 701: Invalid EXPLAIN ANALYZE format: GRAPHVIZ. Supported formats: TEXT, JSON |
| Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 701: Invalid EXPLAIN format: XML. Supported formats: GRAPHVIZ, JSON |
| ``` |
| |
| ## 5. 常见问题 |
| |
| ### 5.1 查询超时时怎么办? |
| |
| `EXPLAIN ANALYZE` 会真实执行查询,因此也可能在查询超时时无法返回完整结果。为辅助排查,IoTDB 会按一定时间间隔将当前分析结果以文本形式写入专用日志;日志间隔根据查询超时时间计算,可保证超时前至少记录两次结果。 |
| |
| 遇到超时时,按以下顺序处理: |
| |
| 1. 查看 `logs/log_explain_analyze.log` 中对应查询的阶段性分析结果。 |
| |
| 2. 如果日志中没有结果,检查升级时是否只替换了 lib 包,而未同步替换 `conf/logback-datanode.xml`。 |
| |
| 3. 替换配置后无需重启。等待配置热加载完成,再执行 `EXPLAIN ANALYZE VERBOSE`。 |
| |
| ### 5.2 WALL TIME 和 CPU TIME 有什么区别? |
| |
| CPU 时间指程序在执行过程中实际占用 CPU 进行计算的时间,表示程序实际消耗的处理器资源。 |
| |
| 墙上时间指从程序开始执行到结束的真实物理时间,包括资源等待时间。 |
| |
| `WALL TIME < CPU TIME` 常见于并行执行场景。例如一个查询分片被两个线程并行执行,物理时间过去 10 秒,但两个线程各占用一个 CPU 核运行 10 秒,则 CPU TIME 约为 20 秒,WALL TIME 约为 10 秒。 |
| |
| `WALL TIME > CPU TIME` 常见于等待资源场景。例如查询分片因内存不足或等待上游数据进入 blocked queue,或者因查询线程资源不足进入 ready queue。等待期间不占用 CPU,但物理时间仍在流逝。 |
| |
| ### 5.3 EXPLAIN ANALYZE 是否有额外开销? |
| |
| 统计信息采集本身几乎没有显著的额外开销。`EXPLAIN ANALYZE` 算子会收集原查询已有的统计信息,并通过 `next` 遍历但不打印查询结果,因此与直接执行同一查询的耗时通常没有显著差别。 |
| |
| 需要注意的是,被分析的查询仍会完整执行并正常消耗 CPU、内存和 IO 资源。评估生产环境影响时,应以原查询本身的资源消耗为准。 |
| |
| ### 5.4 IO 耗时主要关注哪些指标? |
| |
| 涉及 IO 耗时的指标主要包括 `loadBloomFilterActualIOSize`、`loadBloomFilterTime`、`loadTimeSeriesMetadataAlignedDiskSeqTime`、`loadTimeSeriesMetadataAlignedDiskUnseqTime`、`loadTimeSeriesMetadataActualIOSize`、`alignedTimeSeriesMetadataModificationTime`、`constructAlignedChunkReadersDiskTime`、`loadChunkActualIOSize`。 |
| |
| TimeSeriesMetadata 的加载分别统计顺序文件和乱序文件,但 Chunk 的读取暂时未分开统计顺序和乱序比例,可以通过 TimeSeriesMetadata 的顺乱序比例进行估算。 |
| |
| ### 5.5 乱序数据对查询性能的影响如何观测? |
| |
| 乱序数据主要产生两类影响: |
| |
| 1. 查询时需要在内存中多做一次归并排序。 |
| |
| 2. 乱序数据会产生数据块间的时间范围重叠,导致部分统计信息无法直接用于跳过不满足条件的数据块,或无法直接计算聚合值。 |
| |
| 当前没有单独针对乱序数据影响的直接观测指标。通常可以在存在乱序数据时执行一次查询,待乱序数据合并完成后再次执行查询,通过前后耗时对比进行评估。 |