TDengine 逻辑计划生成 — 从 AST 到关系代数算子树

分类 :4.查询引擎 | 篇章:04 逻辑计划

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

逻辑计划(Logical Plan)将语义分析后的 AST 转换为与执行无关的关系代数算子树。这一层抽象屏蔽了具体的存储格式和执行方式,便于做规则化的查询优化(谓词下推、列裁剪、连接重排序等)。

核心概念速查表

概念 说明
Logical Plan 关系代数算子树
Logical Operator 算子节点:Scan/Filter/Project/Agg/Join/Sort 等
Predicate Pushdown 谓词下推(过滤尽早执行)
Column Pruning 列裁剪(只投影需要的列)
Subplan 子计划(用于分布式执行的逻辑单元)
Rewrite Rule 基于规则的重写优化

详细解析

1. 逻辑算子类型

算子 作用 输入/输出
LogicScan 表扫描 输入:表 / 输出:行
LogicFilter 过滤 WHERE 条件
LogicProject 投影 SELECT 列表
LogicAgg 聚合 GROUP BY / 聚合函数
LogicWindow 时间窗口 INTERVAL/SESSION/STATE
LogicSort 排序 ORDER BY
LogicJoin 连接 INNER/LEFT/...JOIN
LogicExchange 节点间数据交换 分布式专用
LogicMerge 多源合并 跨 VGroup 结果合并
LogicFill 填充缺失值 FILL 子句
LogicPartition 分区(按子表) PARTITION BY

2. AST 到 Logical Plan 的转换

复制代码
SQL: SELECT location, AVG(current) 
     FROM meters 
     WHERE ts > now-1h AND voltage > 200 
     GROUP BY location

AST:
  SelectStmt
  ├── select_list: [location, AVG(current)]
  ├── from: meters
  ├── where: ts > now-1h AND voltage > 200
  └── group_by: [location]

转换为 Logical Plan(自底向上构建):

  LogicProject (location, AVG(current))
        │
        ▼
  LogicAgg (group_by=[location], aggs=[AVG(current)])
        │
        ▼
  LogicFilter (ts > now-1h AND voltage > 200)
        │
        ▼
  LogicScan (meters)

3. 基础优化规则

复制代码
规则一:谓词下推(Predicate Pushdown)

  原始计划:
    Filter (ts > T1 AND voltage > 200)
        └── Join (t1 ON t2)
              ├── Scan (t1)
              └── Scan (t2)

  下推后:
    Join
    ├── Filter (ts > T1)         ← 下推到 t1 侧
    │     └── Scan (t1)
    └── Filter (voltage > 200)    ← 下推到 t2 侧
          └── Scan (t2)
  
  效果:减少 Join 输入行数


规则二:列裁剪(Column Pruning)

  原始计划:
    Project (a, b)
        └── Scan (a, b, c, d, e, f)  ← 读取所有列

  优化后:
    Project (a, b)
        └── Scan (a, b)              ← 只读需要的列
  
  效果:减少 I/O 和反序列化


规则三:常量传播

  WHERE a = 5 AND b = a + 3
  → WHERE a = 5 AND b = 8

4. 时序专属优化

复制代码
规则四:时间裁剪(Time Range Cut)

  WHERE ts BETWEEN '2024-01-01' AND '2024-01-02'
  → 标注 LogicScan 的 timeRange = [T1, T2]
  → 后续物理计划阶段用此范围跳过无关 File Set


规则五:Tag 过滤前置(Tag Filter)

  WHERE location = 'BJ' AND ts > now-1h
  → 分离 Tag 条件:location='BJ' → tagFilter
  → 数据条件:ts > now-1h → dataFilter
  → tagFilter 用于子表过滤
  → dataFilter 用于行过滤


规则六:聚合下推到子表

  SELECT location, AVG(current) 
  FROM meters 
  GROUP BY location

  优化为两阶段聚合:
    阶段 1:每个子表内部 → 计算 SUM(current), COUNT(*)
    阶段 2:跨子表合并 → 求总 AVG = SUM/COUNT
  
  优势:
  - 阶段 1 可在 Scan 算子内完成(无需中间物化)
  - 阶段 2 输入数据量大幅减少

5. 子查询展开

复制代码
能展开的子查询:

  SELECT * FROM (
    SELECT ts, current FROM meters WHERE voltage > 200
  ) WHERE ts > now-1h
  
  ↓ 展开
  
  SELECT ts, current FROM meters 
  WHERE voltage > 200 AND ts > now-1h


不能展开的子查询:

  SELECT * FROM (
    SELECT location, AVG(current) AS avg_c 
    FROM meters 
    GROUP BY location
  ) WHERE avg_c > 100
  
  → 子查询有聚合,必须先完成聚合
  → 保留为两层计划:
       Filter (avg_c > 100)
           └── Agg (GROUP BY location)
                 └── Scan (meters)

6. JOIN 重排序

复制代码
连接重排序(小表先 Join):

  SQL: SELECT * FROM big_t 
       JOIN small_t1 ON ...
       JOIN small_t2 ON ...

  优化前:
    Join (big_t, Join(small_t1, small_t2))
    → 大表参与所有 Join,中间结果大

  优化后:
    Join (Join(small_t1, small_t2), big_t)
    → 小表先 Join 缩小中间结果
    → 再与大表 Join
  
  TDengine 主要用于时序数据,JOIN 重排序主要应用于:
  - 维度表 JOIN
  - 多个 Tag 表关联

7. 窗口算子的逻辑表达

复制代码
INTERVAL 窗口的逻辑表示:

  SELECT _wstart, _wend, COUNT(*) 
  FROM meters 
  WHERE ts > now-1d 
  INTERVAL(1h) SLIDING(30m) FILL(NULL)
  
  Logical Plan:
  
    LogicProject (_wstart, _wend, count)
          │
          ▼
    LogicFill (NULL)
          │
          ▼
    LogicWindow (
      type = INTERVAL,
      interval = 1h,
      sliding = 30m,
      aggregations = [COUNT(*)]
    )
          │
          ▼
    LogicFilter (ts > now-1d)
          │
          ▼
    LogicScan (meters)

8. 子计划(Subplan)划分

复制代码
分布式查询的子计划划分:

  单 VGroup 计划(简单情况):
    └── 全部算子在一个 Subplan 中

  跨 VGroup 计划:
    
    Subplan 0(Client/QNode 端):
      Project → Sort → Exchange ← 接收下层数据
    
    Subplan 1(VNode 1):
      Partial Agg → Filter → Scan
      
    Subplan 2(VNode 2):
      Partial Agg → Filter → Scan
      
    Subplan 3(VNode N):
      ...
    
    每个 Subplan 独立调度到对应节点执行
    通过 Exchange 算子连接父子 Subplan

代码示例

查看逻辑计划

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

-- 输出示例:
-- LogicProject
--   LogicAgg [group=location, agg=AVG(current)]
--     LogicFilter [ts > T1]
--       LogicScan [meters, tagFilter=NULL]

优化前后对比

sql 复制代码
-- 优化前(程序生成的低效 SQL)
SELECT * FROM (
  SELECT * FROM meters
) WHERE location='BJ' AND ts > now-1h;

-- 经过子查询展开 + Tag 过滤前置后
-- 实际执行效果等同于:
SELECT * FROM meters WHERE location='BJ' AND ts > now-1h;

性能考量

优化规则的影响

规则 性能影响
谓词下推 减少中间数据量(关键)
列裁剪 减少 I/O 和反序列化
时间裁剪 减少扫描 File Set 数
Tag 过滤前置 减少参与子表数
聚合下推 减少节点间传输
子查询展开 减少物化中间结果

编写 SQL 的最佳实践

建议 原因
WHERE 列尽量"裸用" 让谓词能下推到 Scan
优先选具体列而非 SELECT * 触发列裁剪
Tag 过滤 + 时间过滤 同时享受 Tag 索引和时间裁剪
避免 ORDER BY 全表 排序可能阻止流式输出

FAQ

Q1: 如何确认优化规则被应用了?

使用 EXPLAIN VERBOSE 查看最终的算子树。如果看到 Filter 出现在 Scan 上方而不是 Scan 内部,说明谓词未下推到 Scan 算子(可能因表达式过于复杂)。

Q2: 复杂表达式会被下推吗?

简单的列比较常量(如 a > 5)能下推。涉及函数(如 UPPER(name) = 'A')或多列运算(如 a + b > 10)的下推有限制,部分会保留在 Filter 算子中。

Q3: 为什么我的 WHERE Tag 条件没有用索引?

检查:

  1. 表达式是否裸用 Tag(不是 UPPER(location) = 'BJ'
  2. 是否使用了 OR 跨 Tag 列(可能放弃索引)
  3. 是否有数据列条件混在其中(应该正常分离,但复杂情况下可能失效)

Q4: GROUP BY tbname 与 PARTITION BY tbname 有什么区别?

GROUP BY tbname 是标准 SQL 聚合分组。PARTITION BY tbname 是时序专属语法,按子表分区独立计算,常与窗口函数组合(每个子表独立时间窗口)。

参考

系统构架篇

数据模型

存储引擎

查询引擎

关于 TDengine

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

相关推荐
HAPPY酷1 小时前
软件模拟 I2C vs 硬件 I2C:核心异同与工程选型指南
stm32·单片机·嵌入式硬件·物联网·microsoft
雪兽软件1 小时前
大数据分析:定义、重要性和对企业的好处
大数据·大数据分析
折戟不必沉沙1 小时前
mysql忘记密码
数据库·mysql
A15362551 小时前
六轴工业机械臂厂家怎么选?评估维度与选型参考
大数据·服务器·人工智能
真上帝的左手1 小时前
19. 大数据-技术生态
大数据·big data
阿坤带你走近大数据2 小时前
实时数据开发的一些实战经验
大数据
聪明努力的积极向上2 小时前
【claude code】MySQL MCP 配置完整指南
数据库·mysql·ai编程
AC赳赳老秦2 小时前
OpenClaw + 阿里云 OSS 自动化:批量上传下载文件、自动备份本地数据到云端
运维·数据库·阿里云·自动化·云计算·deepseek·openclaw
数智化管理手记2 小时前
三步轻量化落地法!精益赋能数字化,让工厂转型告别形式化
运维·数据库·人工智能·精益工程