TDengine 常见问题 TOP3

TDengine 常见问题 TOP3

TOP3 主题:流式计算(Stream)相关问题

典型表现:建流失败、结果不符预期、日志狂刷拖慢业务


为什么它是 TOP3

流式计算是 TDengine 最容易被"用错"的功能,也是社区讨论最密集的话题之一:

  • 近 6 周社区里,流计算 相关主题密集出现:《流计算 sql 疑问》《3.4.1.0 流计算日志一直狂刷,导致其它业务受影响》《【流式计算】流式计算聚合各子表指标,数据全部一致是为啥》《官方给看看这流计算怎么执行不了,是 bug 吗》......
  • 它有版本断层 :老版本用 TRIGGER 关键字,新版本已改为 INTERVAL/PERIOD/COUNT_WINDOW 等语法,照抄旧博客/旧文档必然建流失败
  • 它的概念密度高:触发方式、窗口类型、分组、输出表、乱序、水位线、重算......任意一个理解偏差都会导致"建出来了但结果不对",而用户往往以为是 bug。
  • 它的故障会外溢 :流任务异常时会刷大量日志、引发频繁重算,把 CPU/IO 打满,拖慢整个集群的普通 SQL

所以这篇的重点是:先把"结果不对"和"建不出来"的症状分清,再补上概念短板,最后给出正确建流的模板。


一、症状大全(对号入座)

A. 建流失败 / 流不执行

# 报错 / 现象 指向
A1 Invalid stream query0x80002645 流语句非法
A2 Stream not allowed0x8000265A 用了流计算不支持的函数
A3 Stream already exists0x800003F0)/ Stream not exist0x800003F1 流已存在 / 不存在
A4 Too many streams0x800003F6 流数量超限(集群级限制)
A5 Stream temporarily does not support source db having replica > 10x800003F5 源库副本数 > 1
A6 Stream has no stored CREATE statement0x800003F9 流由过低版本创建,元数据不兼容
A7 Stream output table name too long0x80007014)/ Stream output table name calc failed0x80007016 输出子表名规则算不出来或超长
A8 Stream rollup tag path is illegal0x80004118 ROLLUP BY 标签路径非法
A9 Federated query is disabled for stream0x8000411A 流引用了外部源表但未开联邦查询
A10 Snode not deployed0x80000411)、Snode not found0x80000410 集群没部署 snode
A11 Snode already deployed0x8000040F)/ Snode already exists0x800003A4 重复部署 snode
A12 建流语法报错(near "TRIGGER" 之类) 用了旧版 TRIGGER 语法
A13 流建好了,但数据写进去完全没反应,查询结果表始终为空 snode 缺失 / 触发条件不满足
A14 Stream task not exist0x80004100 流任务丢失,需查服务端日志

B. 结果不符预期(最高频)

# 现象 指向
B1 各子表的聚合结果完全一致 漏了 PARTITION BY tbname
B2 流计算导致数据重复插入多条 输出表设计 / 重复触发
B3 窗口边界不对,_wstart / _wend 与预期不符 窗口偏移 / 时区问题
B4 TWA 等计算结果不符合预期 窗口与过滤条件用法问题
B5 同一分组、同一时间戳的结果互相覆盖 输出表主键设计问题
B6 部分计算结果凭空消失 结果主键为 NULL 被丢弃
B7 历史数据没有被计算 未指定 FILL_HISTORY / FILL_HISTORY_FIRST
B8 计数窗口在开头无法正常衔接 COUNT_WINDOW 未优先计算历史数据
B9 业务边界被跨越(如订单切换时把两组数据配成一对) 未用 STATE_WINDOW 划分业务边界

C. 日志与资源

# 现象 指向
C1 流计算日志一直狂刷,CPU / IO wait 很高,应用无操作也一样 频繁重算 / 流任务异常
C2 简单 SQL 执行都变慢 同上,snode 与 taosd 混部导致资源抢占
C3 ins_streams 中显示大量重算、进度落后、错误信息 乱序写入严重
C4 Rsma stream state open / commit0x80003154 / 0x80003155 流算子状态存储失败

D. 维护操作类

# 报错 / 现象 指向
D1 Snode still in use with streams0x80007007 还有流在用,不能删 snode
D2 Db used by stream0x8000700E 库被流引用,不能删
D3 Stream must be dropped first0x800003F3 依赖对象不能先删
D4 DROP SNODE 失败 snode 或其副本不在线
D5 RECALCULATE STREAM 一直 Pending / Running 重算在后台执行中,或区间不合法

E. 版本与语法断层

# 现象 指向
E1 照抄文档/博客建流报语法错误 TRIGGER 仅适用于 v3.0.0.0--v3.3.7.0
E2 升级后原有流不工作 建流语句需要改造
E3 流数量受限、提示授权不足 Stream creation limited by license0x80000807

二、原因分析

2.1 流计算的执行链路

#mermaid-svg-cQY2bDDgBgrmtOFC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cQY2bDDgBgrmtOFC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cQY2bDDgBgrmtOFC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cQY2bDDgBgrmtOFC .error-icon{fill:#552222;}#mermaid-svg-cQY2bDDgBgrmtOFC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cQY2bDDgBgrmtOFC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cQY2bDDgBgrmtOFC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cQY2bDDgBgrmtOFC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cQY2bDDgBgrmtOFC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cQY2bDDgBgrmtOFC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cQY2bDDgBgrmtOFC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cQY2bDDgBgrmtOFC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cQY2bDDgBgrmtOFC .marker.cross{stroke:#333333;}#mermaid-svg-cQY2bDDgBgrmtOFC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cQY2bDDgBgrmtOFC p{margin:0;}#mermaid-svg-cQY2bDDgBgrmtOFC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cQY2bDDgBgrmtOFC .cluster-label text{fill:#333;}#mermaid-svg-cQY2bDDgBgrmtOFC .cluster-label span{color:#333;}#mermaid-svg-cQY2bDDgBgrmtOFC .cluster-label span p{background-color:transparent;}#mermaid-svg-cQY2bDDgBgrmtOFC .label text,#mermaid-svg-cQY2bDDgBgrmtOFC span{fill:#333;color:#333;}#mermaid-svg-cQY2bDDgBgrmtOFC .node rect,#mermaid-svg-cQY2bDDgBgrmtOFC .node circle,#mermaid-svg-cQY2bDDgBgrmtOFC .node ellipse,#mermaid-svg-cQY2bDDgBgrmtOFC .node polygon,#mermaid-svg-cQY2bDDgBgrmtOFC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cQY2bDDgBgrmtOFC .rough-node .label text,#mermaid-svg-cQY2bDDgBgrmtOFC .node .label text,#mermaid-svg-cQY2bDDgBgrmtOFC .image-shape .label,#mermaid-svg-cQY2bDDgBgrmtOFC .icon-shape .label{text-anchor:middle;}#mermaid-svg-cQY2bDDgBgrmtOFC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cQY2bDDgBgrmtOFC .rough-node .label,#mermaid-svg-cQY2bDDgBgrmtOFC .node .label,#mermaid-svg-cQY2bDDgBgrmtOFC .image-shape .label,#mermaid-svg-cQY2bDDgBgrmtOFC .icon-shape .label{text-align:center;}#mermaid-svg-cQY2bDDgBgrmtOFC .node.clickable{cursor:pointer;}#mermaid-svg-cQY2bDDgBgrmtOFC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cQY2bDDgBgrmtOFC .arrowheadPath{fill:#333333;}#mermaid-svg-cQY2bDDgBgrmtOFC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cQY2bDDgBgrmtOFC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cQY2bDDgBgrmtOFC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cQY2bDDgBgrmtOFC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cQY2bDDgBgrmtOFC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cQY2bDDgBgrmtOFC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cQY2bDDgBgrmtOFC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cQY2bDDgBgrmtOFC .cluster text{fill:#333;}#mermaid-svg-cQY2bDDgBgrmtOFC .cluster span{color:#333;}#mermaid-svg-cQY2bDDgBgrmtOFC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cQY2bDDgBgrmtOFC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cQY2bDDgBgrmtOFC rect.text{fill:none;stroke-width:0;}#mermaid-svg-cQY2bDDgBgrmtOFC .icon-shape,#mermaid-svg-cQY2bDDgBgrmtOFC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cQY2bDDgBgrmtOFC .icon-shape p,#mermaid-svg-cQY2bDDgBgrmtOFC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cQY2bDDgBgrmtOFC .icon-shape .label rect,#mermaid-svg-cQY2bDDgBgrmtOFC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cQY2bDDgBgrmtOFC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cQY2bDDgBgrmtOFC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cQY2bDDgBgrmtOFC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端

CREATE STREAM ...
mnode

生成 DAG / 分发任务
snode

执行流任务
触发表

(vnode)
数据源表

(vnode)
输出表

(vnode)
NOTIFY

WebSocket 通知

三条铁律(不理解这三条,一定会踩坑):

  1. 必须先有 snode,才能建流。 snode 是专门跑流任务的节点,集群里至少要有 1 个;不部署 snode 时流根本无法执行。
  2. 触发与计算是分离的。 触发来源叫"触发表",计算的数据来源叫"数据源表",两者可以不是同一张表。如果不同,必须确保触发发生时数据源表的数据已经写入完成,否则结果会错。
  3. 输出表由主键(时间戳 + 分组键)决定唯一性。 同分组同时间戳会互相覆盖;主键为 NULL 的结果会被直接丢弃。

2.2 根因归类

类别 说明 对应症状
① 没部署 snode 集群里流计算节点缺失 A10 A13
② 语法/版本不匹配 用了旧版 TRIGGER 或过时写法 A12 E1 E2
③ 分组理解错误 超级表场景漏 PARTITION BY tbname,导致所有子表结果被聚合到一组 B1 B5
④ 触发方式选错 定时 / 窗口 / 计数 / 事件窗口用错场景 B3 B8 B9 A13
⑤ 输出表设计错误 输出表名规则、主键、TAG 设计不当 A7 B2 B5 B6
⑥ 乱序与重算 写入乱序导致频繁重算,结果反复覆盖 B2 B4 C1 C3
⑦ 历史数据未处理 建流前的存量数据没算 B7 B8
⑧ 资源抢占 snode 与 taosd 混部,流负载打满 CPU/IO C1 C2
⑨ 依赖对象被误删 直接删库/snode 而流还在引用 D1 D2 D3 D4

三、先搞懂流计算:触发方式、分组、输出表

流计算的结果错误,绝大多数不是 bug,而是触发方式 / 分组 / 输出表这三件事没想清楚。

3.1 第一步:部署 snode(建流的前置条件)

sql 复制代码
-- 在指定 dnode 上创建 snode(每个 dnode 最多 1 个)
CREATE SNODE ON DNODE <dnode_id>;

-- 查看
SHOW SNODES;
SELECT * FROM information_schema.ins_snodes;

部署建议

  • 把 snode 部署在独立 dnode(该节点不再部署 vnode / mnode / qnode),做资源隔离,避免流任务拖慢读写。
  • 部署多个 snode(分布在多个物理节点)以获得负载均衡与高可用;每两个 snode 互为副本。
  • 只部署 1 个 snode 时,系统不提供高可用保证。
  • 流负载高时,增加 snode 即可横向扩展。

DROP SNODE 时必须保证 snode 及其副本同时在线,否则会失败(D4)。

3.2 第二步:选对触发方式

触发类型 语法 适用场景
定时触发 PERIOD(period_time[, offset_time]) 按处理时间定时运算,可无触发表
滑动触发 SLIDING(...) 根据事件时间定时运算
时间窗口触发 INTERVAL(...) SLIDING(...) 固定窗口聚合,最常用
计数窗口触发 COUNT_WINDOW(count[, sliding][, col]) 每写入 N 条数据处理一次
事件窗口触发 EVENT_WINDOW(START WITH ... END WITH ...) 满足条件开窗、满足条件关窗
会话 / 状态窗口 SESSION(...) / STATE_WINDOW(...) 按业务边界(如订单切换)划分

硬性约束(最容易踩):

  • 状态窗口、事件窗口、计数窗口搭配超级表时,必须与 PARTITION BY tbname 一起使用。
  • 时间窗口触发必须指定触发表
  • 定时触发可以没有触发表;但若要分组输出或使用 %%trows,则必须指定触发表。

3.3 第三步:想清楚分组

业务目标 分组方式
全局聚合(所有子表合成一个结果) 不分组
按标签聚合(如按区域、设备类型) PARTITION BY <tag_name>
每个子表各自一个结果(最常见) PARTITION BY tbname

PARTITION BY tbname 是超级表场景的默认答案。 社区里"各子表聚合结果完全一致"(B1)100% 是漏了这一句------不加分组时,所有子表的数据被当作一组聚合,结果当然一样。

3.4 第四步:设计输出表

sql 复制代码
-- 每个分组独立输出子表(最直观)
CREATE STREAM sm1 INTERVAL(5m) SLIDING(5m)
  FROM stb1 PARTITION BY tbname
  INTO stb2 AS
    SELECT _twstart, avg(col1) FROM %%tbname
     WHERE _c0 >= _twstart AND _c0 <= _twend;

关键点:

  • 输出表名超长/算不出来 → 检查 OUTPUT_SUBTABLE(tbname_expr) 规则与是否有 NULL(A7)。
  • 多个分组合并到一个子表 → 让这些分组使用相同的输出表名,并设计好复合主键,否则会互相覆盖(B5)。
  • 结果主键为 NULL 会被丢弃(B6)------确保时间戳列与分组键不为空。
  • 选择 %%trows 还是 FROM %%tbname
写法 含义
FROM %%trows 只使用触发时读取到的窗口数据(快照)
FROM %%tbname WHERE _c0 >= _twstart AND _c0 <= _twend 查询该分组对应表在窗口内的数据,计算时数据可能已变化

3.5 第五步:处理乱序与历史数据

需求 选项
容忍一定乱序 WATERMARKPERIOD 定时触发不生效
忽略乱序数据(时效性优先) STREAM_OPTIONS(IGNORE_DISORDER)
丢弃过期数据 STREAM_OPTIONS(EXPIRED_TIME(exp_time))
需要计算建流前的历史数据 STREAM_OPTIONS(FILL_HISTORY)
优先计算历史数据(计数窗口场景必须) STREAM_OPTIONS(FILL_HISTORY_FIRST)
删除数据也要重算 STREAM_OPTIONS(DELETE_RECALC)(仅 COUNT_WINDOW(1) / COUNT_WINDOW(n,1) 支持)
极高实时性要求 STREAM_OPTIONS(LOW_LATENCY_CALC)(对资源要求更高)

四、标准排查流程(照着做)

第 1 步:确认版本与语法

sql 复制代码
-- 服务端版本
SELECT server_version();
  • v3.0.0.0 ~ v3.3.7.0:可用 TRIGGER 关键字。
  • 更高版本:必须使用新语法INTERVAL / PERIOD / COUNT_WINDOW / EVENT_WINDOW / SESSION / STATE_WINDOW)。
  • 不要照抄旧博客的建流语句,以当前版本文档为准。

第 2 步:确认 snode 已部署

sql 复制代码
SHOW SNODES;
SELECT * FROM information_schema.ins_snodes;
  • 没有任何 snode → 先部署,再建流CREATE SNODE ON DNODE <id>;)。
  • snode 离线 → 检查对应 dnode 服务与网络。

第 3 步:查看流任务状态

sql 复制代码
-- 流列表与状态
SELECT * FROM information_schema.ins_streams;

-- 重算请求跟踪
SELECT * FROM information_schema.ins_stream_recalculates;

重点关注:

  • 是否有错误信息;
  • 实时计算是否持续保持进度一致(进度落后说明处理不过来);
  • 重算次数 / 比例是否异常偏高(说明乱序严重)。
sql 复制代码
-- 确认创建语句
SHOW CREATE STREAM [db_name.]stream_name;

第 4 步:检查触发与分组是否正确

对照第三节的四个问题自查:

  1. 触发方式选对了吗?(定时 / 窗口 / 计数 / 事件)
  2. 超级表 + 状态/事件/计数窗口时,加 PARTITION BY tbname 了吗?
  3. 触发表与数据源表是同一张吗?不同的话,触发时数据源表数据写完了吗?
  4. 输出表名、主键、TAG 设计会导致覆盖吗?

结果"每张子表都一样" → 99% 是第 2 条。

第 5 步:检查是否有乱序写入

TDengine 的乱序定义 :从时间戳 0 起按 DURATION 参数(默认 10 天)划分时间窗口,同一窗口内写入的时间戳未按顺序写入即算乱序。窗口之间交错不算。

sql 复制代码
-- 查看库的 DURATION 设置
SHOW CREATE DATABASE <db_name>;

处理方式(按业务容忍度选择):

  • 大概率可容忍 → 指定 WATERMARK
  • 时效性优先、不影响结果 → IGNORE_DISORDER
  • 过期数据且结果已无意义 → EXPIRED_TIME
  • 写入侧尽量保证同一子表的数据由同一消费者顺序写入(Kafka 场景尤其重要)。

第 6 步:检查日志狂刷与资源占用

bash 复制代码
# 看 snode 与 taosd 的日志
tail -300 /var/log/taos/taosdlog

# 看 CPU / IO
top -Hp $(pgrep taosd)

# 集群 vgroup 状态
taos -s "show vgroups;"

若确认是频繁重算导致:

sql 复制代码
-- 关闭自动重算(若业务能接受最终一致性风险)
-- 通过流选项控制;也可考虑降低流的并发/线程配置

终极手段:把 snode 迁到独立 dnode,做资源隔离。

第 7 步:需要补算历史数据时

sql 复制代码
-- 手动重算(SQL 返回成功只代表请求被接受,不代表已完成)
RECALCULATE STREAM [db_name.]stream_name FROM start_time [TO end_time];

注意事项:

  • 不适用于 PERIOD 定时触发
  • 计数窗口手动重算必须同时指定开始与结束时间,否则请求会被忽略;
  • 重算不会删除输出表中已产生的结果,可能与新结果同时存在,必要时先清理结果表区间;
  • recalc_idinformation_schema.ins_stream_recalculates 跟踪进度;
  • 处于 Pending / Running不要重复提交相同请求

五、典型场景实操

场景 1:建流报语法错误(旧语法)

现象 :照抄旧文档,CREATE STREAM ... TRIGGER ... 报语法错误。

原因TRIGGER 仅适用于 v3.0.0.0--v3.3.7.0

改造对照

sql 复制代码
-- 旧写法(仅 3.3.7.0 及以前)
CREATE STREAM s1 TRIGGER SLIDING(5m) FROM stb1 ...

-- 新写法
CREATE STREAM s1 INTERVAL(5m) SLIDING(5m) FROM stb1 ...
sql 复制代码
-- 旧:定时
CREATE STREAM s2 TRIGGER PERIOD(1h) ...

-- 新:定时
CREATE STREAM s2 PERIOD(1h) ...

场景 2:各子表聚合结果完全一致

现象 :超级表下每个子表的 avg/min/max 结果一模一样。

原因 :漏了 PARTITION BY tbname

正确写法

sql 复制代码
CREATE STREAM IF NOT EXISTS nbq_hourly
  INTERVAL(1h) SLIDING(1h)
  FROM product_nbq
  PARTITION BY tbname                    -- ← 关键
  INTO product_nbq_hourly
  AS
    SELECT
      _wstart                          AS ts,
      tbname                           AS device_id,
      CAST(AVG(current_value) AS DECIMAL(16,4)) AS avg_value,
      MAX(current_value)               AS max_value
    FROM %%tbname
    WHERE _c0 >= _twstart AND _c0 <= _twend;

场景 3:流建好了但完全不计算

排查顺序

sql 复制代码
-- ① snode 有没有
SHOW SNODES;

-- ② 流在不在、状态如何
SELECT * FROM information_schema.ins_streams;

-- ③ 触发条件是否被满足
--    计数窗口:写入条数够不够
--    事件窗口:START 条件是否出现过
--    时间窗口:窗口是否已经关闭(未关闭不触发,除非指定 MAX_DELAY)
sql 复制代码
-- 新建表后需要数据写入才会触发,可先造数据验证
INSERT INTO tb1 VALUES (NOW, 1.0);

场景 4:日志狂刷、CPU 打满、业务变慢

原因:乱序写入 → 频繁重算 → 计算与日志双重压力。

操作

sql 复制代码
-- ① 看流的重算情况
SELECT * FROM information_schema.ins_streams;
SELECT * FROM information_schema.ins_stream_recalculates;

-- ② 评估乱序容忍度,重新建流并加上合适的选项
CREATE STREAM sm_fixed
  INTERVAL(5m) SLIDING(5m)
  FROM stb1 PARTITION BY tbname
  STREAM_OPTIONS(IGNORE_DISORDER | MAX_DELAY(1m))
  INTO stb2 AS
    SELECT _twstart, avg(col1) FROM %%tbname
     WHERE _c0 >= _twstart AND _c0 <= _twend;
bash 复制代码
# ③ 资源隔离:把 snode 部署到独立 dnode
#    在该 dnode 上不部署 vnode/mnode/qnode

场景 5:结果重复写入

现象:输出表里同一批数据出现多条。

原因(按概率)

  1. 同一个分组多次触发产生相同主键 → 正常应互相覆盖;若表没有主键约束或时间戳计算有误,就会重复。
  2. 多个分组输出到同一个子表但主键设计不当。
  3. 手动重算后没有清理结果表。

操作

sql 复制代码
-- 检查输出表主键设计
DESCRIBE <output_table>;

-- 重算前先清理该区间结果
DELETE FROM <output_table> WHERE ts >= '<start>' AND ts < '<end>';

场景 6:会话/订单类业务边界被跨越

现象 :用 COUNT_WINDOW(2,1) 计算相邻两条差值时,把上一订单的最后一条和下一订单的第一条配成了一对。

正确做法 :外层用 STATE_WINDOW 定义业务边界,内层再计算:

sql 复制代码
CREATE STREAM order_pair
  STATE_WINDOW(order_id) AS                                    -- 外层:业务边界
  WINDOW(COUNT_WINDOW(2, 1) AS pair)                           -- 内层:计算粒度
  FROM charging_pile
  STREAM_OPTIONS(EVENT_TYPE(WINDOW_CLOSE))
  INTO order_pair_results
  AS
    SELECT _twstart, soc_delta FROM pair;

注意 :非叶 STATE_WINDOW 必须指定 EXTEND(1);触发表为超级表且窗口链包含 STATE_WINDOW / EVENT_WINDOW / COUNT_WINDOW 时,必须 PARTITION BY tbname

场景 7:计算建流前的历史数据

sql 复制代码
-- 优先算历史(计数窗口场景建议)
CREATE STREAM sm_hist
  INTERVAL(5m) SLIDING(5m)
  FROM stb1 PARTITION BY tbname
  STREAM_OPTIONS(FILL_HISTORY_FIRST)
  INTO stb2 AS
    SELECT _twstart, avg(col1) FROM %%tbname
     WHERE _c0 >= _twstart AND _c0 <= _twend;
  • FILL_HISTORY:也计算历史数据;
  • FILL_HISTORY_FIRST优先计算历史数据;
  • 计数窗口若不优先算历史,可能导致窗口无法衔接

场景 8:删除 snode / 数据库失败

sql 复制代码
-- 删 snode 前先确认没有流在用它
SHOW SNODES;
SELECT * FROM information_schema.ins_streams;

-- 报 Snode still in use with streams → 先删相关流
DROP STREAM <stream_name>;

-- 报 Db used by stream → 先删引用该库的流
-- 确认 snode 及其副本都在线后再删
DROP SNODE ON DNODE <dnode_id>;

六、错误码速查

错误码 报错文本 含义 处理方向
0x80002645 Invalid stream query 非法流语句 修正 SQL
0x8000265A Stream not allowed 函数不能在流中使用 换函数
0x800003F0 Stream already exists 流已存在 改名字
0x800003F1 Stream not exist 流不存在 确认库名/流名
0x800003F3 Stream must be dropped first 有依赖不能删 先删流
0x800003F5 Stream ... source db having replica > 1 源库副本数受限 调整副本数
0x800003F6 Too many streams 流数量超限 精简流
0x800003F9 Stream has no stored CREATE statement 低版本建的流 重建流
0x8000040F / 0x80000410 / 0x80000411 Snode already deployed / not found / not deployed snode 状态问题 部署/检查 snode
0x80000411 Snode not deployed 未部署 snode CREATE SNODE ON DNODE <id>
0x80000807 Stream creation limited by license 流数量超授权 联系交付
0x80003154 / 0x80003155 Rsma stream state open / commit 流算子状态存储失败 查日志,联系开发
0x80004100 Stream task not exist 流任务不存在 查服务端日志
0x80004118 Stream rollup tag path is illegal ROLLUP BY 路径非法 修正路径
0x8000411A Federated query is disabled for stream 外部源引用未开联邦查询 开启 federatedQueryEnable 或移除引用
0x80007007 Snode still in use with streams snode 被流占用 先删流
0x8000700E Db used by stream 库被流引用 先删流
0x80007014 / 0x80007016 Stream output table name too long / calc failed 输出表名问题 检查命名规则与 NULL
0x80007017 Stream vtable calculate need redeploy 虚拟表分布变更 流会自动处理,无需干预
0x80007018 Stream info contains invalid JSON 内部编码兼容问题 保留现场,上报 issue

七、预防清单

  • 建流前先部署 snode ,并尽量部署在独立 dnode
  • 集群部署多个 snode 做负载均衡与高可用(单 snode 无高可用保证)。
  • 以当前版本文档为准写建流 SQL ,不要照抄旧博客的 TRIGGER 写法。
  • 超级表场景默认加 PARTITION BY tbname
  • 明确"触发表"与"数据源表"的关系,确保触发时数据已写完。
  • 输出表:设计好输出表名规则 + 主键 + TAG,避免覆盖与丢弃。
  • 写入侧尽量保证顺序(Kafka 一个子表一个消费者),从源头减少重算。
  • 按业务容忍度设置 WATERMARK / IGNORE_DISORDER / EXPIRED_TIME
  • 需要历史数据时显式指定 FILL_HISTORY / FILL_HISTORY_FIRST
  • 定期查 ins_streams进度一致性、重算比例、错误信息
  • 流负载高时通过增加 snode 扩容,而不是硬扛。
  • 删库/删 snode 前先确认没有流在引用。

八、求助模板(贴在社区里,回复会快很多)

text 复制代码
【TDengine 使用环境】生产 / 预生产 / 测试 / PoC
【TDengine 版本】服务端:x.x.x.x   客户端:x.x.x.x
【操作系统及版本】___
【部署方式】容器 / 非容器
【集群节点数】___    【副本数】___    【snode 数量】___
【问题类型】建流失败 / 结果不符预期 / 日志狂刷 / 维护操作失败
【完整建流语句】(把 CREATE STREAM 全文贴出来,这是最关键的信息)
【现象描述】期望结果 vs 实际结果
【已排查】
  - SHOW SNODES:___
  - SELECT * FROM information_schema.ins_streams:___
  - SHOW CREATE STREAM <name>:___
  - 触发表写入是否有序:___
  - 服务端版本:___
【日志】/var/log/taos/taosdlog 关键片段 + /etc/taos 配置

九、相关链接


本文整理自 TDengine 技术社区真实提问,覆盖 3.0 至 3.4 各版本的流式计算相关问题。如果你遇到的情况不在上述症状列表中,欢迎到社区发帖并附上本文第八节的求助模板。

相关推荐
Leo.yuan3 小时前
盘点2026十大主流国产数据仓库软件:从开源到商业,企业级怎么选?
大数据
长谷深风1113 小时前
评测AI Agent:三种裁判各司其职
java·大数据·开发语言·人工智能·ai agent
D_codingXuChu3 小时前
2026年物联网应用开发服务商怎么选:从设备接入到业务闭环的采购评估指南
物联网·技术分享·开发经验
螺蛳粉 螺蛳粉3 小时前
MySQL 分布式集群系列 · 第五篇——全方位对比:NDB、MGR、主从复制、分库分表怎么选?
数据库·分布式·mysql
大大大大晴天4 小时前
元数据之后,数据治理该做什么:标准、指标与主数据
大数据
移动云开发者联盟5 小时前
AI重塑短剧生产!移动云×咪咕 AIGC内容创作平台正式发布
大数据·人工智能
YCOSA20255 小时前
BUG修复---雨晨 Windows 11 IoT 企业版 LTSC 23H2 终结版 22631.7588
windows·物联网
其实防守也摸鱼5 小时前
Codex 下载与本地部署实战:从安装到运行全指南
android·大数据·运维·安全·自动化
shujudang7 小时前
零售客户分析平台的四种路径:身份关联、分析模型与系统对接
大数据·人工智能·数据分析