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

相关推荐
ai_coder_ai1 小时前
编写自动化脚本,在自己后端服务中使用云原生Baas服务进行编码和解码相关操作
数据库·云原生·自动化
廋到被风吹走2 小时前
【AI】GPT-5.6三模型齐发、世界模型崛起、Anthropic冲刺IPO
大数据·人工智能·gpt
@灯神2 小时前
SpringAI系列|第1篇:SpringAI概述与快速上手
java·人工智能·spring·ai·ai编程
hehelm2 小时前
AI 大模型接入 SDK —项目概述
linux·服务器·网络·数据库·c++
中国搜索直付通2 小时前
避开直付通选型暗礁:二级商户的合规生存与背景甄别
java·大数据·开发语言·人工智能·游戏
Database_Cool_2 小时前
阿里云 Lindorm vs Elasticsearch 检索存储一体对比:多模数据库一站式方案首选
数据库·阿里云
无忧智库2 小时前
产业经济大脑建设方案:用数据驱动“产业研判、精准招商、企业服务与经济智治”(PPT)
大数据
leoZ2312 小时前
Git 集成实战完全指南(六):Git 标签与版本管理
大数据·git·elasticsearch
大郭鹏宇2 小时前
下篇:LangChain Agent 智能体从入门到实战(二)—— 记忆管理、中间件与最佳实践
网络·数据库·人工智能