TDengine 物理计划生成 — 算子下沉、Exchange 与 Subplan 切分

分类 :4.查询引擎 | 篇章:05 物理计划

适用版本:TDengine v3.x(v3.3.x / v3.4.x) | 最后更新:2026-06-12

物理计划(Physical Plan)将逻辑算子映射为具体的物理算子实现,确定算子的执行节点(VNode/QNode/Client),插入 Exchange 节点完成数据流转,最终输出可被 Scheduler 直接调度的 Subplan 集合。

核心概念速查表

概念 说明
Physical Operator 物理算子(Table Scan、Hash Agg、Merge Join 等)
Subplan 一个执行单元,对应一个节点(VNode/QNode)的任务
Exchange Operator 跨节点数据传输算子
DataSink Subplan 的输出端,将数据发给上层
DAG Subplan 之间形成的有向无环图
Two-Phase Aggregation 两阶段聚合(Partial + Final)

详细解析

1. 物理算子分类

复制代码
TDengine 主要物理算子:

  扫描类:
  - TableScan / TagScan / SystemTableScan
  - StreamScan
  
  过滤投影:
  - Filter / Project
  
  聚合类:
  - Hash Aggregate(GROUP BY)
  - Stream Aggregate(已排序数据流式聚合)
  - Partial / Final Aggregate(两阶段)
  
  窗口类:
  - Interval Window
  - Session Window
  - State Window
  - Event Window
  - Count Window
  
  排序合并:
  - Sort / Merge / SortMerge
  
  连接类:
  - Hash Join / Merge Join / Nested Loop Join
  
  数据流:
  - Exchange(接收)
  - DataDispatch(发送)

2. 逻辑算子到物理算子的映射

逻辑算子 候选物理算子 选择依据
LogicScan TableScan / TagScan 是否只查 Tag
LogicFilter Filter 通用
LogicAgg HashAgg / StreamAgg 输入是否已排序
LogicWindow IntervalWindow / SessionWindow 窗口类型
LogicSort Sort / MergeSort 输入是否多路
LogicJoin HashJoin / MergeJoin 数据量与排序性

3. 两阶段聚合下沉

复制代码
SELECT location, AVG(current) FROM meters GROUP BY location

逻辑计划:
  LogicAgg (GROUP BY location, AVG(current))
        └── LogicScan (meters)

物理计划(两阶段):

  ┌─ Subplan 0 (Client/QNode) ─────────────────┐
  │  Final Aggregate                            │
  │    AVG = SUM(partial_sum) / SUM(partial_cnt)│
  │  ↑                                          │
  │  Exchange ← 接收 Subplan 1/2/N 的结果      │
  └────────────────────────────────────────────┘
              ▲
  ┌───────────┼───────────┬─────────────┐
  │           │           │             │
  ┌─ Subplan 1 ─┐  ┌─ Subplan 2 ─┐  ┌─ Subplan N ─┐
  │ DataSink    │  │ DataSink    │  │ DataSink    │
  │ Partial Agg │  │ Partial Agg │  │ Partial Agg │
  │  SUM(c),    │  │  SUM(c),    │  │  SUM(c),    │
  │  COUNT(*)   │  │  COUNT(*)   │  │  COUNT(*)   │
  │ TableScan   │  │ TableScan   │  │ TableScan   │
  └─────────────┘  └─────────────┘  └─────────────┘
   (VNode 1)        (VNode 2)        (VNode N)

  优势:
  - VNode 内本地聚合,输出从万行减少到几行
  - Exchange 传输量极小
  - Final 聚合开销低

4. Exchange 算子的工作模式

复制代码
Exchange 的三种数据传输模式:

  ① ShuffleExchange(按 Key 重分发):
     场景:跨节点 GROUP BY 大量分组键
     行为:发送端按 Key Hash 决定接收方
     接收端按 Key 收集到对应桶
     
  ② PartitionExchange(保持分区):
     场景:PARTITION BY tbname
     行为:每个子表的数据完整发到同一接收端
     接收端独立计算每个分区
     
  ③ MergeExchange(按序合并):
     场景:跨节点 ORDER BY ts
     行为:每个 VNode 内已按 ts 排序
     接收端做 K-way Merge
     
  选择策略:
  - 数据已有序 + 需要全局有序 → MergeExchange
  - 按 Key 分组 → ShuffleExchange
  - 按分区独立处理 → PartitionExchange

5. Subplan 切分规则

复制代码
Subplan 边界的判定:

  规则:算子需要跨节点数据 → 插入 Exchange → 切分 Subplan

  示例:
  SELECT location, AVG(current)
  FROM meters
  WHERE ts > now-1h
  GROUP BY location

  Subplan 切分:
  
  Subplan 0 (Client)
    Final Aggregate
    Exchange (接收 Subplan 1~N)
  
  Subplan 1 (VNode 1)
    DataSink (发到 Subplan 0)
    Partial Aggregate
    Filter (ts > now-1h)
    TableScan (meters, vgId=1)
  
  Subplan 2 (VNode 2)
    DataSink (发到 Subplan 0)
    Partial Aggregate
    Filter (ts > now-1h)
    TableScan (meters, vgId=2)
  
  ... 直到所有 VGroup

6. 时序专属物理算子

复制代码
INTERVAL 窗口物理算子选择:

  SELECT _wstart, COUNT(*) FROM meters INTERVAL(1h)
  
  数据已按 ts 排序的优势:
  ① StreamIntervalWindow(流式):
     - 输入按 ts 有序
     - 维护当前窗口状态
     - ts 跨入新窗口 → 输出当前窗口结果
     - 内存占用 O(1)(只保留当前窗口)
     
  vs HashIntervalWindow:
     - 输入无序时使用
     - 用哈希表保存所有未关闭窗口
     - 内存占用 O(N)(N = 窗口数)
  
  TDengine 优先选择 StreamIntervalWindow(数据天然有序)


SESSION/STATE 窗口:
  - 必须按 ts 顺序扫描
  - 边界由数据内容决定(不是固定时间)
  - 算子维护当前会话/状态

7. 限制性子句的物理实现

复制代码
LIMIT 与 OFFSET:

  LIMIT N 下推:
    SELECT * FROM meters LIMIT 10
    → 每个 VNode 各取 10 行(Partial LIMIT)
    → Exchange 接收最多 10*N 行
    → Final 阶段 LIMIT 10
    
  ORDER BY + LIMIT 优化:
    SELECT * FROM meters ORDER BY ts DESC LIMIT 10
    → 每个 VNode 内有序 → 取最后 10 行
    → Exchange 阶段 K-way Merge 取前 10
    → 无需全量排序

OFFSET 的代价:
  OFFSET 1000000 → 需要先读取并丢弃前 100 万行
  → 大 OFFSET 性能极差
  → 推荐用时间范围或 Tag 过滤代替分页

8. 不同查询类型的物理计划差异

查询类型 物理特点
单子表点查 单 Subplan,无 Exchange
单超级表无聚合 跨 VGroup Scan + Merge
单超级表聚合 两阶段 Agg + Exchange
跨库 JOIN Hash Join + 多 Subplan
窗口聚合 StreamWindow + 两阶段
嵌套子查询 多层 Exchange

代码示例

查看物理计划

sql 复制代码
EXPLAIN VERBOSE 
SELECT location, AVG(current) 
FROM meters 
WHERE ts > now-1h 
GROUP BY location;

-- 输出会显示:
-- - Subplan 0: AggregateMerge + ExchangeReceiver
-- - Subplan 1..N: AggregatePartial + TableScan

强制使用 QNode

sql 复制代码
-- 提示查询使用 QNode(如果集群配置了)
SELECT /*+ USE_QNODE */ COUNT(*) FROM big_table;

观察 Exchange 数据量

sql 复制代码
EXPLAIN ANALYZE 
SELECT location, COUNT(*) 
FROM meters 
GROUP BY location;

-- 关注 Exchange 节点的:
-- - rows_input: 接收的行数
-- - bytes_input: 接收的字节数
-- → 越小说明 Partial Agg 越有效

性能考量

Subplan 数量对性能的影响

Subplan 数 适用场景 注意
1 单子表点查 最简单,无网络开销
数十 中等规模聚合 平衡并行度与协调开销
数百 大规模分析 调度开销可能成为瓶颈
数千 不推荐 应考虑预聚合或分批查询

Exchange 优化要点

要点 说明
尽量在叶子节点 Partial Agg 减少 Exchange 数据量
利用数据有序性 用 MergeExchange 替代 Sort
避免无谓的全量传输 LIMIT/Tag 过滤下推

FAQ

Q1: 为什么我的查询只有一个 Subplan?

可能原因:

  • 只查一个子表(命中单一 VGroup)
  • 时间范围内只有一个 VGroup 有数据
  • 使用了不分区的 META 表查询

这是高效的------无 Exchange 开销。

Q2: 两阶段聚合一定更快吗?

大部分情况是。但极端场景(如分组键基数巨大且无重复,Partial Agg 无收益)可能反而增加开销。规划器会根据估算决定是否启用。

Q3: 物理计划缓存吗?

参数化查询(STMT)的物理计划会被复用。普通文本 SQL 每次都重新生成。如需高频执行相同结构的查询,强烈推荐使用 STMT。

Q4: 能手动控制 Subplan 切分吗?

目前不支持直接干预。可以通过 hint(如 USE_QNODE)影响算子放置,或通过改写 SQL(如 CTE/子查询)间接影响。

参考

系统构架篇

数据模型

存储引擎

查询引擎

关于 TDengine

TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。

相关推荐
sunshine8851 小时前
ISO 27001与PCI-DSS认证:财务数据安全如何反哺业财一体化落地?
大数据·人工智能
swordbob1 小时前
MYSQL RR 解决“脏读+不可重复读“和“幻读“的本质区别
数据库·mysql
IvorySQL1 小时前
PostgreSQL 全球对话:开源链接世界,共建共治共享
数据库·postgresql·开源
Nontee2 小时前
新手数据库进阶:大白话图解四大隔离级别与底层机制
数据库·oracle
dishugj2 小时前
【YashanDB 认证】我的崖山数据库初体验:从陌生到上手的成长之路
数据库
yxl874646462 小时前
磐创PCTG-9013 Modbus转ProfibusDP工业协议转换器
网络·科技·物联网·gateway·信息与通信
前端 贾公子2 小时前
Claude Code 的 skills 源码解析 (上)
数据库·人工智能
吠品2 小时前
.NET 8 单文件发布:把 exe 和一堆 dll 打进一个文件里
服务器·数据库·windows
MetrixAeroCore2 小时前
德国物联网卡出海适配解析|西欧合规组网通信方案(MetrixAeroCore)
物联网