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 类型速查表

类型 关键字 行为
Inner JOIN / INNER JOIN 双侧匹配
Left Outer LEFT JOIN / LEFT OUTER JOIN 保留左侧
Right Outer RIGHT JOIN / RIGHT OUTER JOIN 保留右侧
Full Outer FULL JOIN / FULL OUTER JOIN 保留双侧
Semi LEFT SEMI JOIN 左侧存在匹配则保留
Anti LEFT ANTI JOIN 左侧无匹配则保留
ASOF LEFT ASOF JOIN 时间近邻
Window WINDOW 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

sql 复制代码
-- 基本
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

sql 复制代码
-- 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

sql 复制代码
-- 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(时间近邻)

sql 复制代码
-- 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(时间窗口)

sql 复制代码
-- 找出每个事件前后窗口内的关联记录
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

sql 复制代码
-- 与聚合子查询 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 中含复杂表达式

代码示例

综合场景

sql 复制代码
-- 同设备两类传感器对齐
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;

与子查询配合

sql 复制代码
-- 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 提供实时分析、可视化、事件管理与报警等功能。

相关推荐
ClouGence10 分钟前
告别 Navicat!CloudDM:开源免费一站式数据库开发管理工具
数据库·sql·开源·数据库开发
灵析表格11 分钟前
灵析表格功能函数深度分析报告
前端·数据库·microsoft
Data_Journal12 分钟前
掌握网页抓取中的分页:完整指南
java·服务器·前端
莫逸风14 分钟前
【AgentScope 2.0】05-文件系统(Filesystem)详解
java·ai·agent·springai·agentscope
jaboo1215 分钟前
postgresql从入门到精通
数据库·postgresql·langchain
晴天¥20 分钟前
记一次Oracle集群归档日志爆满之后如何处理(涉及ASM磁盘的增添。有坑必踩)
数据库·oracle
云边有个稻草人27 分钟前
Ubuntu部署Prometheus与Alertmanager:服务接入和远程监控
数据库·ubuntu·prometheus
Hoxy.R29 分钟前
记录一次Oracle 19c RAC iSCSI会话反复重连:comm error (1020) 原因定位与解决
数据库·oracle
腾渊信息科技公司32 分钟前
Spring Boot集成TDengine实战:工业时序数据存储选型与迁移方案
spring boot·后端·tdengine