当前位置: 首页 > news >正文

TDengine 连接算子 — Inner/Outer/ASOF/Window Join 的实现与使用

分类:4.查询引擎 |篇章:08 连接算子

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

JOIN 是关系数据库的核心能力。TDengine 在标准 SQL JOIN(Inner/Left/Right/Full)之外,针对时序场景额外提供 ASOF JOIN(按时间近邻)和 Window JOIN(按时间窗口),让"两个设备时间序列对齐"这类需求一行 SQL 即可表达。

核心概念速查表

概念说明
Hash Join用哈希表的等值连接
Merge Join输入已排序时的连接
Inner Join仅返回两侧匹配的行
Outer JoinLEFT/RIGHT/FULL 保留一侧或两侧
ASOF Join时间近邻连接(找最接近的时间点)
Window Join时间窗口连接(同窗口内对齐)
Equi Join Condition等值连接条件(必须含时间等值)

详细解析

1. TDengine JOIN 的时间约束

TDengine 的 JOIN 核心要求: ✓ JOIN 必须包含时间戳等值条件(普通 JOIN) 或时间相关条件(ASOF / Window JOIN) 示例(合法): SELECT * FROM t1 JOIN t2 ON t1.ts = t2.ts; SELECT * FROM t1 JOIN t2 ON t1.ts = t2.ts AND t1.id = t2.id; ✗ 不合法: SELECT * FROM t1 JOIN t2 ON t1.id = t2.id; -- 缺少时间条件 原因: - 时序数据按时间分布 - 没有时间约束的 JOIN 是笛卡尔积级别的开销 - 强制时间条件保证可优化为窗口对齐

2. Inner Join 与 Outer Join

JOIN 类型对比: 数据示例: t1: t2: ts=T1, v=10 ts=T1, v=100 ts=T2, v=20 ts=T3, v=300 ts=T3, v=30 INNER JOIN (ts=ts): T1: (10, 100) T3: (30, 300) [T2 不匹配,被丢弃] LEFT JOIN: T1: (10, 100) T2: (20, NULL) ← 保留左侧 T3: (30, 300) RIGHT JOIN: T1: (10, 100) T3: (30, 300) [t1 中无 T2 也无影响,因为 RIGHT 保留右侧] FULL OUTER JOIN: T1: (10, 100) T2: (20, NULL) T3: (30, 300)

3. ASOF JOIN(时间近邻)

ASOF JOIN 场景: 设备 A 每秒采集,设备 B 每 5 秒采集 问题:A 的每个时间点对应的 B 最近一次采集? 数据: A: T1, T2, T3, T4, T5, T6, T7, T8 B: T1, T6 ASOF JOIN A LEFT ASOF JOIN B ON A.ts >= B.ts: 每个 A.ts 找到 B 中 <=A.ts 的最大者 A.T1 → B.T1 A.T2 → B.T1 A.T3 → B.T1 A.T4 → B.T1 A.T5 → B.T1 A.T6 → B.T6 A.T7 → B.T6 A.T8 → B.T6 语法: SELECT a.ts, a.v, b.v FROM ta a ASOF JOIN tb b ON a.ts >= b.ts AND a.id = b.id -- Tag 等值约束(可选); 支持的比较操作: >, >=, <, <=

4. Window JOIN(时间窗口)

Window JOIN 场景: 问题:每对设备的同一分钟内的关联事件 Window JOIN tb b WINDOW(1m) ON ta.id = tb.id: 每个 ta 的行,找 tb 中 [ta.ts - 30s, ta.ts + 30s] 内的所有行 示例: ta: T1=12:00:10, T2=12:00:50 tb: B1=12:00:15, B2=12:01:30 ta=T1 → tb 在 [11:59:40, 12:00:40] → B1 匹配 ta=T2 → tb 在 [12:00:20, 12:01:20] → 无匹配 语法: SELECT * FROM ta WINDOW JOIN tb WINDOW(1m) -- 窗口大小 ON ta.id = tb.id;

5. Hash Join 实现

Hash Join 的两阶段: 阶段 1:构建(Build) 选择较小的表(构建侧) 读取所有行 → 构建哈希表(Key = JOIN 键) 阶段 2:探测(Probe) 扫描较大的表(探测侧) 对每行:用 JOIN 键查找哈希表 匹配则输出 示例: SELECT * FROM big JOIN small ON big.id = small.id AND big.ts = small.ts Build (small): 哈希表: (id=1, ts=T1) → row_data (id=1, ts=T2) → row_data (id=2, ts=T1) → row_data Probe (big): 扫描 big 每行 查询哈希表是否有匹配 特点: ✓ 适合 = 等值连接 ✓ 大小表组合 ✗ 构建侧必须放入内存

6. Merge Join 实现

Merge Join(输入已排序): 前提:两侧输入按 JOIN 键有序 算法: 指针 i 指向 t1 第一行 指针 j 指向 t2 第一行 while i < len(t1) and j < len(t2): if t1[i].key == t2[j].key: 输出 (t1[i], t2[j]) i++ 或 j++(处理重复键) elif t1[i].key < t2[j].key: i++ else: j++ TDengine 中的时间 JOIN 天然适合 Merge Join: - 两侧数据都按 ts 有序 - 不需要构建哈希表 - 内存占用 O(1) - 适合海量数据

7. JOIN 的分布式执行

跨 VGroup 的 JOIN 执行: SELECT * FROM ta JOIN tb ON ta.ts = tb.ts AND ta.id = tb.id ta 跨 VGroup 1, 2 tb 跨 VGroup 3, 4 执行选项: ① 广播 JOIN(适合小表): - 小表(如 tb)拉取到所有 ta 所在节点 - 每个 ta 节点本地 Hash Join ② Shuffle JOIN(适合大表): - 两侧都按 JOIN 键 Shuffle 到相同节点 - 各节点 Hash/Merge Join - 适合大表 + 大表 ③ 单子表 JOIN(最简单): - 如果 ta 和 tb 都是子表 - 通常单 VGroup 内完成 - 无需 Shuffle

8. JOIN 性能调优

JOIN 性能关键点: ① 选择性优先: 先过滤再 JOIN SELECT * FROM ta JOIN tb ON ta.ts=tb.ts WHERE ta.location='BJ' AND tb.location='BJ' → 过滤下推到 Scan → JOIN 输入数据量减少 ② 时间范围必须明确: SELECT * FROM ta JOIN tb ON ta.ts=tb.ts WHERE ta.ts > now-1h → 同时限制 ta 和 tb 的时间范围 ③ 数据局部性: 同 VGroup 的子表 JOIN → 无 Shuffle 跨 VGroup 的 JOIN → Shuffle 开销

代码示例

基础 JOIN

-- 两个超级表的时间对齐SELECTa.ts,a.current,b.powerFROMelectric_meters aJOINpower_meters bONa.ts=b.tsANDa.location=b.locationWHEREa.ts>now-1h;-- LEFT JOIN 保留所有 ASELECTa.ts,a.current,b.powerFROMelectric_meters aLEFTJOINpower_meters bONa.ts=b.tsANDa.location=b.location;

ASOF JOIN

-- 高频设备对低频参考值SELECTa.ts,a.current,b.standard_voltageFROMrealtime_sensor aLEFTASOFJOINreference_sensor bONa.ts>=b.tsANDa.location=b.locationWHEREa.ts>now-1h;

Window JOIN

-- 找出每个温度异常前后 1 分钟的湿度记录SELECTt.tsAStemp_ts,h.tsAShumi_ts,t.temperature,h.humidityFROMtemperature_log t WINDOWJOINhumidity_log h WINDOW(1m)ONt.location=h.locationWHEREt.temperature>40ANDt.ts>now-1d;

性能考量

JOIN 类型选择

场景推荐 JOIN
等频率采集对齐INNER JOIN ON ts
不同采集频率对齐LEFT ASOF JOIN
事件关联(同窗口内任意点)WINDOW JOIN
维度表关联INNER JOIN(含 Tag 等值)

性能优化清单

  • WHERE 同时限制两侧的时间范围
  • WHERE 同时过滤两侧的 Tag(让数据局部化)
  • 优先选具体列,避免 SELECT *
  • 小表放右侧(可能影响 Build/Probe 选择)
  • 大基数 JOIN 考虑 QNode

FAQ

Q1: 为什么我的 JOIN 报"missing time condition"?

TDengine 要求 JOIN 必须有时间相关条件。改写:

  • 普通 JOIN:ON ... AND t1.ts = t2.ts
  • 时间近邻:用ASOF JOIN
  • 时间窗口:用WINDOW JOIN

Q2: ASOF JOIN 性能如何?

输入按 ts 有序时(时序数据天然如此),用 Merge 风格算法,复杂度 O(N+M)。生产环境处理百万级数据行毫秒~秒级。

Q3: 多表 JOIN(≥3)支持吗?

支持但复杂度高,每多一张表 JOIN 次数线性增加。建议:

  • 拆分为多个简单查询
  • 用应用层组合
  • 或预先 ETL 到宽表

Q4: JOIN 和 UNION 哪个更适合?

  • JOIN:横向合并(增加列)
  • UNION:纵向合并(增加行)
  • 多设备同类数据汇总用 UNION
  • 多种数据类型对齐用 JOIN

参考

系统构架篇

  • 01-《TDengine 整体架构全景》
  • 02-《集群拓扑深度解析》
  • 03-《MNode 内部机制深度解析》
  • 04-《RPC 通信层深度解析》
  • 05-《VNode 生命周期》
  • 06-《RAFT 共识协议》
  • 07-《端到端的消息流》

数据模型

  • 01-《数据库创建与参数详解》
  • 02-《超级表/子表/普通表》
  • 03-《支持数据类型深度解析》
  • 04-《TDengine Tag 设计哲学与 Schema 变更机制》
  • 05-《TDengine 虚拟表实现原理》

存储引擎

  • 01-《TDengine 存储引擎概览》
  • 02-《TDengine MemTable 深度解析》
  • 03-《TDengine WAL 预写日志机制》
  • 04-《TDengine 数据文件格式》
  • 05-《TDengine Commit 与 Flush 机制 》
  • 06-《TDengine Compaction 合并策略 》
  • 07-《TDengine 数据保留与 TTL》
  • 08-《TDengine 压缩编码机制》
  • 09-《TDengine Cache 与 Last 查询加速》
  • 10-《TDengine 逻辑计划生成》

查询引擎

  • 01-《TDengine 查询引擎概览》
  • 02-《TDengine SQL 解析与词法分析》
  • 03-《TDengine 语义分析与 AST 重写》
  • 04-《TDengine 逻辑计划生成》
  • 05-《TDengine 物理计划生成》
  • 06-《TDengine 扫描算子》
  • 07-《TDengine 聚合算子》
http://www.jsqmd.com/news/1022408/

相关文章:

  • 拼多多流量底层逻辑:免费自然流量+付费推广搭配玩法,新手也能快速起店
  • 国产超声波位差计十大品牌排名 - 仪表人小余
  • 2026武汉爱彼回收怎么选更踏实?我跑了五家平台,把最真实的经历写出来 - 逸程
  • Windows 11 LTSC微软商店终极安装指南:3分钟恢复完整应用生态
  • FPGA学习全攻略:从数字电路基础到VGA贪吃蛇实战
  • 2026安庆商户高频选择的 5 家公共卫生第三方检测机构实地测评整理 公共场所 + 水质卫生检测 附电话地址 - 鉴安检测
  • 2026绵阳旧金铂金白银回收高信赖门店 TOP 线下实体商家电话与门店地址一览 - 诚金汇钻回收公司
  • 如何高效使用智能游戏工具:5个提升英雄联盟体验的实用技巧
  • 【JAVA毕设源码分享】基于SpringBoot和Vue的社区儿童玩具交易系统设计与实现(程序+文档+代码讲解+一条龙定制)
  • 扩散模型记忆化问题与RADS框架解决方案
  • 2026河源当地贵金属回收权威名录 TOP5 黄金金条铂金白银回收线下门店信息汇总 - 信誉隆金银铂奢回收
  • 2026河北建筑工程材料检测 CMA 机构哪家强?TOP 正规检测中心榜单 + 电话地址 - 中检检测集团
  • 【万字文档+源码】基于springboot+vue病历管理系统-可用于毕设-课程设计-练手学习-学习资料分享
  • Android 开发问题:EditText 控件的 android:imeOptions=“actionDone“ 属性不生效
  • Spring EL实战:多对象入参实现优惠券动态可用规则校验
  • 百色全城贵金属回收优选门店 TOP5 黄金回收铂金回收白银回收正规商家地址汇总 - 中安检金银铂钻回收
  • 一天一个昇腾 Agent-Skills 小技巧:实现 SAM 3.1 模型的 Ascend OM 路线适配
  • 天津回收黄金门店推荐2026天津黄金回收商家实力排行榜,高价变现首选 - 名奢变现站
  • 2026淮南旧金铂金白银回收高信赖门店 TOP 线下实体商家电话与门店地址一览 - 诚金汇钻回收公司
  • 大数据转行运营、财会的难度高不高?证书规划与职业破局指南
  • 【JAVA毕设源码分享】基于java的爱心小屋捐赠系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 【万字文档+源码】基于springboot+vue校园朋友圈微信小程序-可用于毕设-课程设计-练手学习-学习资料分享
  • ProgAgent:解决强化学习灾难性遗忘的进度感知方法
  • 5分钟告别手动画线:通达信ChanlunX缠论插件终极自动化解决方案
  • 基于多个统计模型估算中国氮和硫沉积(2005-2020)
  • CVAT本地化部署指南:Docker Compose实战与AI辅助标注配置
  • 2026甘南建筑工程材料检测 CMA 机构哪家强?TOP 正规检测中心榜单 + 电话地址 - 中检检测集团
  • 2026年10款论文降AI率软件亲测:从90%降至10%的靠谱之选
  • 板球百年概率预测:基于50分临界点的实时二分类建模
  • 2026甘肃商户高频选择的 5 家公共卫生第三方检测机构实地测评整理 公共场所 + 水质卫生检测 附电话地址 - 鉴安检测