TDengine JOIN 完整语法 — Inner/Outer/ASOF/Window 全语法详解

分类:10.SQL 参考 | 篇章:04 JOIN 完整语法
在这里插入图片描述

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

TDengine JOIN 在标准 SQL 基础上扩展了时序专属的 ASOF 和 Window JOIN。本文是 JOIN 语法的完整参考,含每种类型的语义、条件约束、典型用例。

JOIN 类型速查表

类型关键字行为
InnerJOIN / INNER JOIN双侧匹配
Left OuterLEFT JOIN / LEFT OUTER JOIN保留左侧
Right OuterRIGHT JOIN / RIGHT OUTER JOIN保留右侧
Full OuterFULL JOIN / FULL OUTER JOIN保留双侧
SemiLEFT SEMI JOIN左侧存在匹配则保留
AntiLEFT ANTI JOIN左侧无匹配则保留
ASOFLEFT ASOF JOIN时间近邻
WindowWINDOW JOIN时间窗口对齐

详细解析

1. 时间条件约束(重要)

所有 JOIN 必须满足时间相关性:

  ✓ 普通 JOIN:必须含 t1.ts = t2.ts 或时间等值
  ✓ ASOF JOIN:必须含 t1.ts <op> t2.ts 时间比较
  ✓ WINDOW JOIN:内置时间窗口
  
  ✗ 不允许的 JOIN:
    SELECT * FROM t1 JOIN t2 ON t1.id = t2.id;  -- 缺时间

2. Inner JOIN

-- 基本
SELECT t1.ts, t1.current, t2.power 
FROM electric_meters t1 
JOIN power_meters t2 ON t1.ts = t2.ts;

-- 多条件
SELECT * FROM t1 JOIN t2 
ON t1.ts = t2.ts 
  AND t1.location = t2.location;

-- 多表(注意性能)
SELECT * FROM t1 JOIN t2 ON t1.ts = t2.ts 
                JOIN t3 ON t1.ts = t3.ts;


语义:
  保留 ON 条件同时满足的行
  双侧 ts 都存在且相等

3. Outer JOIN

-- LEFT JOIN
SELECT t1.ts, t1.current, t2.power 
FROM electric_meters t1 
LEFT JOIN power_meters t2 ON t1.ts = t2.ts;
-- t1 保留所有,t2 无匹配为 NULL

-- RIGHT JOIN
SELECT t1.ts, t1.current, t2.power 
FROM electric_meters t1 
RIGHT JOIN power_meters t2 ON t1.ts = t2.ts;
-- t2 保留所有

-- FULL OUTER JOIN
SELECT t1.ts, t1.current, t2.power 
FROM electric_meters t1 
FULL JOIN power_meters t2 ON t1.ts = t2.ts;
-- 双侧都保留

4. Semi/Anti JOIN

-- SEMI JOIN: 左侧存在匹配则保留(去重)
SELECT * FROM users u 
LEFT SEMI JOIN orders o ON u.id = o.user_id AND u.ts = o.ts;
-- 等价于:SELECT * FROM users WHERE id IN (SELECT user_id FROM orders)

-- ANTI JOIN: 左侧无匹配则保留
SELECT * FROM users u 
LEFT ANTI JOIN orders o ON u.id = o.user_id AND u.ts = o.ts;
-- 等价于:SELECT * FROM users WHERE id NOT IN (...)

5. ASOF JOIN(时间近邻)

-- LEFT ASOF JOIN:每个左侧 ts 找右侧近邻
SELECT a.ts, a.current, b.standard_voltage 
FROM realtime a 
LEFT ASOF JOIN reference b 
  ON a.ts >= b.ts 
  AND a.location = b.location;

-- 支持比较:>= > <= <
-- >= 找 <= 当前的最大者
-- <= 找 >= 当前的最小者


-- 限制条件:必须有时间比较
LEFT ASOF JOIN ... ON a.ts >= b.ts [AND tag_eq_conditions]

-- 多列等值(Tag 关联)
LEFT ASOF JOIN reference b 
  ON a.ts >= b.ts 
  AND a.factory = b.factory 
  AND a.line = b.line;

6. WINDOW JOIN(时间窗口)

-- 找出每个事件前后窗口内的关联记录
SELECT t.ts AS event_ts, h.ts AS related_ts, t.value, h.value 
FROM events t 
WINDOW JOIN history h 
  WINDOW(1m)         -- 窗口大小 ±30s
  ON t.location = h.location 
WHERE t.value > 100;


-- 窗口语义:
-- 每个 t 的 ts 为中心,[ts - window/2, ts + window/2]
-- 找出 h 中落在该窗口的所有行
-- 一对多关系

7. 子查询 + JOIN

-- 与聚合子查询 JOIN
SELECT m.ts, m.current, h.hist_avg 
FROM meters m 
JOIN (
  SELECT tbname, AVG(current) AS hist_avg 
  FROM meters 
  WHERE ts < now-1d 
  PARTITION BY tbname
) h ON m.tbname = h.tbname 
WHERE m.ts > now-1h;

8. JOIN 性能限制

注意:
  ① TDengine 推荐 JOIN 数量 ≤ 5
  ② 时间窗口必须明确(不能 ts > 0)
  ③ 同 VGroup 子表 JOIN 最优
  ④ 跨 VGroup 大表 JOIN 需 Shuffle,慎用


高效 JOIN 模式:
  - 两侧都有时间过滤
  - 两侧都有 Tag 过滤
  - 时间和 Tag 条件配对


低效 JOIN:
  - 无时间过滤的全表 JOIN
  - 多张超级表全字段 JOIN
  - JOIN 中含复杂表达式

代码示例

综合场景

-- 同设备两类传感器对齐
SELECT 
  t.ts, t.current AS amperage,
  v.voltage AS voltage,
  t.current * v.voltage AS power
FROM current_sensor t 
JOIN voltage_sensor v 
  ON t.ts = v.ts AND t.device_id = v.device_id 
WHERE t.ts > now-1h;


-- 高频数据对齐低频参考
SELECT 
  m.ts, m.value, r.threshold 
FROM minutely_data m 
LEFT ASOF JOIN reference_data r 
  ON m.ts >= r.ts AND m.device_type = r.device_type 
WHERE m.value > r.threshold 
  AND m.ts > now-1d;


-- 事件前后关联
SELECT 
  a.ts AS alarm_ts, 
  m.ts AS measure_ts, 
  m.current 
FROM alarm a 
WINDOW JOIN meters m 
  WINDOW(5m) 
  ON a.device_id = m.tbname 
WHERE a.severity = 'CRITICAL' 
  AND a.ts > now-1d;

与子查询配合

-- TOP N + JOIN 详情
SELECT top.tbname, top.avg_c, m.ts, m.current 
FROM (
  SELECT tbname, AVG(current) AS avg_c 
  FROM meters 
  WHERE ts > now-1d 
  PARTITION BY tbname 
  ORDER BY avg_c DESC 
  LIMIT 10
) top 
JOIN meters m ON top.tbname = m.tbname 
WHERE m.ts > now-1h;

性能考量

JOIN 性能影响

因素影响
双侧时间过滤决定扫描量
Tag 过滤决定子表数
JOIN 表数量复杂度指数级
跨 VGroup需要 Shuffle
ASOF 的输入有序输入有序时 O(N+M)

优化建议

建议原因
限制时间范围关键
列出具体列减少传输
JOIN 不超过 3 表避免组合爆炸
大表 + 小表用 INNER利于 Hash Join
数据局部化避免 Shuffle

FAQ

Q1: 为什么 JOIN 必须有时间条件?

时序数据按时间分布,无时间条件的 JOIN 等同于笛卡尔积,开销极大。强制时间条件防止误用。

Q2: ASOF JOIN 性能如何?

输入按 ts 有序时(时序天然如此),用 Merge 风格 O(N+M)。生产环境百万行毫秒~秒级。

Q3: 一条 JOIN 能跨数据库吗?

支持跨数据库:FROM db1.t1 JOIN db2.t2 ON ...。但跨集群 JOIN 不支持。

Q4: JOIN 结果集很大如何处理?

  • 加 LIMIT
  • 加更严格的过滤条件
  • 改用流计算预先 JOIN

Q5: JOIN 中的 NULL 处理?

NULL 不与 NULL 相等。Outer JOIN 中无匹配的列填 NULL。

参考

系统构架篇

数据模型

存储引擎

查询引擎

数据写入

数据订阅

预聚合

索引

SQL 语句

关于 TDengine

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TDengine (老段)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值