news 2026/9/13 8:40:29

TDengine TSMA(时间范围小型物化聚合)完全指南:创建、查询优化与限制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TDengine TSMA(时间范围小型物化聚合)完全指南:创建、查询优化与限制

TDengine TSMA(时间范围小型物化聚合)完全指南:创建、查询优化与限制

【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine

导读

在 TDengine 中,当历史数据量持续增长、查询时间跨度扩展到天、月甚至年级别时,聚合查询需要扫描的原始数据块数量会急剧增加,查询耗时随之上升。TSMA(Time-Range Small Materialized Aggregates,时间范围小型物化聚合)允许用户为超表(supertable)或普通表(basic table)指定固定时间窗口,将窗口内的聚合结果预先计算并存储,使后续查询直接读取预计算结果而无需扫描原始数据。本文基于 01-tsma.md 文档,结合 TDengine 开源仓库源码,系统讲解 TSMA 的创建语法、支持的聚合函数、查询匹配规则、使用限制与相关配置参数,帮助你在实际业务中正确设计与使用 TSMA 加速长时间范围的聚合查询。

TSMA 是什么:从块内 SMA 到时间窗口物化

TDengine 的数据存储按数据块(block)组织,每个数据块内部本身就携带 SMA(Small Materialized Aggregates,小型物化聚合)信息,例如块内某列的最小值、最大值、和等。当查询时间范围较小、只覆盖少量数据块时,直接利用块内 SMA 即可显著减少扫描量。

但当查询时间范围达到天、月甚至年时,涉及的数据块数量非常庞大,块内 SMA 的粒度过小,无法有效加速查询。TSMA 正是为解决这一问题而生:它支持用户显式指定一个时间窗口(例如 5 分钟、1 小时、1 天),把窗口内的数据预先聚合,并将计算结果落盘存储。后续查询在窗口完全对齐的情况下,可以直接从预计算结果中取值,从而大幅提升查询性能。

TSMA 的计算结果以一张用户不可见的超表形式存放在原表所在的库中,该结果表无法被用户直接删除,会在执行DROP TSMA时自动清理。

创建 TSMA

基本语法

-- 基于超表或普通表创建 TSMA CREATE TSMA tsma_name ON [dbname.]table_name FUNCTION (func_name(func_param) [, ...] ) INTERVAL(time_duration); -- 基于更小窗口的 TSMA 创建更大窗口的 TSMA(递归 TSMA) CREATE RECURSIVE TSMA tsma_name ON [db_name.]tsma_name1 INTERVAL(time_duration); time_duration: number unit

两种创建方式的核心差异在于:

  • 直接创建:指定 TSMA 名称、目标表名、聚合函数列表和窗口大小;
  • 递归创建(RECURSIVE):基于一个已存在的 TSMA 创建窗口更大的新 TSMA,此时不能指定FUNCTION(),新 TSMA 继承源 TSMA 的函数列表;指定的INTERVAL必须是源 TSMA 窗口长度的整数倍,且存在额外约束——小时级只能基于 1h(不能基于 2h、3h),月级只能基于 1d(不能基于 2d、3d)。

从语法解析层面看,TDengine 在 source/libs/parser/inc/sql.y#L1536-L1550 中实现了两类命令:cmd ::= CREATE TSMA ...cmd ::= CREATE RECURSIVE TSMA ...,其中函数列表通过tsma_func_list(A) ::= FUNCTION NK_LP func_list(B) NK_RP解析,TSMA 名称tsma_name复用普通标识符NK_ID规则。

命名规则

TSMA 的命名规则与表名类似,最大长度为表名长度上限减去输出表后缀长度。表名长度上限为 193,输出表后缀为_tsma_res_stb_,因此 TSMA 名称最大长度为 178。

创建约束

  • 仅支持基于超表和普通表创建,不能基于子表(subtable)创建
  • 函数列表只能包含受支持的聚合函数(见下文函数表),且每个函数的参数必须是单一参数——即使该函数原生支持多参数,此处也只能传一个;参数必须是普通列名,不能是标签列(tag column)。
  • 函数列表中出现相同的函数与列组合会被去重,例如同时创建两个avg(c1)时,只会计算并输出一份结果。
  • TSMA 计算会把所有函数的中间结果输出到另一张超表,该表会包含原表的全部标签列,外加 4 个附加列:_wstart(窗口开始时间)、_wend(窗口结束时间)、_wduration(窗口时长),以及一个新标签列tbname
  • 函数数量上限:函数个数最多为「表的列数上限(含标签列)减去 TSMA 计算占用的 4 个附加列,再减去原表的标签列数」。超过该限制会报Too many columns错误。
  • 行宽限制:TSMA 输出本身是一张超表,其行长度受最大行长度限制。不同函数的中间结果大小不一,通常大于原始数据大小。若输出表行长度超限,会报Row length exceeds max length错误,此时应减少函数数量,或将常用函数拆分成多个 TSMA。
  • 窗口大小限制[1m ~ 1y/12n],其中INTERVAL的单位与查询中INTERVAL子句的单位一致,参见 时间单位说明。
  • 全局唯一与数量上限:TSMA 是库内对象,但其名称在整个集群内全局唯一。集群内可创建的 TSMA 总数受服务端参数maxTsmaNum限制。由于 TSMA 的后台计算基于流式计算(stream computing),每个 TSMA 创建时都会占用一个流,因此可创建的 TSMA 数量同时受当前已有流数量与流上限的制约。

maxTsmaNum在 source/common/src/tglobal.c#L1179 中注册,定义如下:

cfgAddInt32(pCfg, "maxTsmaNum", tsMaxTsmaNum, 0, 10, CFG_SCOPE_SERVER, CFG_DYN_SERVER, CFG_CATEGORY_GLOBAL, CFG_PRIV_SYSTEM);

即默认值为 10,取值范围[0, 10],属于服务端全局配置且支持动态调整(CFG_DYN_SERVER)。

支持的聚合函数列表

函数说明
min最小值
max最大值
sum求和
first窗口内首条记录值
last窗口内末条记录值
avg平均值
count若需使用count(*),应创建count(ts)函数
spread极差(最大值与最小值之差)
stddev标准差

注意count的使用方式:TSMA 中不能直接创建count(*),而应创建count(ts)来表达“统计记录数”的语义。

删除 TSMA

DROP TSMA [db_name.]tsma_name;

若待删除的 TSMA 被其他 TSMA 作为基础(存在递归 TSMA 依赖),删除操作会报错:Invalid drop base tsma, drop recursive tsma first。因此必须先删除所有基于它创建的递归 TSMA,再删除基础 TSMA。

DROP TSMACREATE TSMASHOW CREATE TSMA一起被纳入权限体系管理,见 source/common/src/tpriv.c#L231-L234,其中DROP TSMA对应PRIV_CM_DROP权限。

TSMA 计算原理

TSMA 的计算通过流式计算完成,是一个后台异步过程

  • 计算结果不保证实时精确,但能保证最终正确性(ultimate correctness)
  • 当原表的某个子表没有数据时,可能不会创建对应的输出子表。因此即使配置了countAlwaysReturnValuecount查询也不会返回该表的计数结果;
  • 当存在大量历史数据时,创建 TSMA 后,流式计算会先回算历史数据,此期间新建的 TSMA 不会被查询使用;
  • 数据发生更新、删除或数据过期时,受影响的数据会被自动重新计算;重算期间,TSMA 查询结果不保证实时精确。

若希望查询实时数据,有两种途径绕过 TSMA:

  1. 在 SQL 中增加 Hint:/*+ skip_tsma() */
  2. 将客户端参数querySmaOptimize设置为0

相关配置参数

服务端参数:maxTsmaNum

  • 位置:taosd 服务端配置,见 taosd 配置参数;
  • 默认值:10;取值范围:[0, 10]
  • 作用:限制整个集群内可创建的 TSMA 总数。

客户端参数

以下参数均在 taosc 客户端配置中,详见 taosc 查询相关配置:

参数说明默认值取值范围
querySmaOptimize查询时是否使用 TSMA:1使用预计算结果,0查询原始数据00/1
maxTsmaCalcDelay单位秒,控制可接受的 TSMA 计算延迟。当 TSMA 计算进度与最新时间之差在该值范围内时使用该 TSMA,否则不使用600(10 分钟)最小 600(10 分钟),最大 86400(1 天)
tsmaDataDeleteMark单位毫秒,与流式计算参数deleteMark一致,控制流式计算中中间结果的保留时长1d(86400000 ms)最小1h(3600000 ms)

tsmaDataDeleteMark的语义需要特别关注:距离最后一条数据超过该时长的历史窗口不会保留中间结果。如果这些历史窗口中的数据被修改,TSMA 结果可能得不到更新,从而与查询原始数据的结果不一致。

这三个客户端参数在 source/common/src/tglobal.c 中均有注册与默认值定义:

// L774: querySmaOptimize, client, 0 ~ 1 cfgAddInt32(pCfg, "querySmaOptimize", tsQuerySmaOptimize, 0, 1, CFG_SCOPE_CLIENT, CFG_DYN_CLIENT, ...); // L854: maxTsmaCalcDelay, client, 600 ~ 86400 cfgAddInt32(pCfg, "maxTsmaCalcDelay", tsMaxTsmaCalcDelay, 600, 86400, CFG_SCOPE_CLIENT, ...); // L856: tsmaDataDeleteMark, client, 60*60*1000 ~ INT64_MAX, 默认 86400000ms cfgAddInt32(pCfg, "tsmaDataDeleteMark", tsmaDataDeleteMark, 60 * 60 * 1000, INT64_MAX, ...);

同时,tsmaDataDeleteMark在查询解析阶段会被转换为与表时间精度一致的单位参与计算,见 source/libs/parser/src/parTranslater.c#L29057。

使用 TSMA 进行查询

窗口匹配与选择策略

TSMA 中定义的聚合函数可以直接用于大多数查询场景:

  • 未指定窗口大小的查询:默认优先使用「包含查询中全部聚合函数」且窗口最大的 TSMA。例如SELECT COUNT(*) FROM stable GROUP BY tbname会使用包含count(ts)且窗口最大的 TSMA。因此,如果聚合查询使用频繁,应尽量创建大窗口的 TSMA。
  • 指定窗口大小的查询:即查询语句带INTERVAL时,使用最大的、可被整除(divisible)的窗口 TSMA。在窗口查询中,INTERVALOFFSETSLIDING三个值都会影响可用 TSMA 窗口大小——可被整除的窗口指 TSMA 窗口大小能被查询语句的INTERVAL, OFFSET, SLIDING整除。因此,若窗口查询使用频繁,创建 TSMA 时应综合考虑常用查询窗口、offset 与 sliding 的大小。

示例 1:创建了5m10m两个窗口的 TSMA 后:

  • 查询INTERVAL(30m)时,优先使用10m的 TSMA;
  • 查询INTERVAL(30m, 10m) SLIDING(5m)时,只有5m的 TSMA 能被使用。

多窗口存在时,优先选择窗口更大的 TSMA;未封口(unsealed)的窗口会通过查询更小窗口的 TSMA 或原始数据来计算。若某个场景完全无法使用 TSMA,整个查询会退回原始数据计算。

查询匹配示例

下面结合文档中的完整示例说明匹配与不匹配的情形。假设:

CREATE TSMA tsma1 ON stable FUNCTION(COUNT(ts), SUM(c1), SUM(c3), MIN(c1), MIN(c3), AVG(c1)) INTERVAL(1m);
查询是否使用 tsma1原因
SELECT COUNT(*), SUM(c1) + SUM(c3) FROM stable;✅ 使用函数均被定义
SELECT COUNT(*), AVG(c1) FROM stable GROUP/PARTITION BY tbname, tag1, tag2;✅ 使用按标签分组不受影响
SELECT COUNT(*), MIN(c1) FROM stable INTERVAL(1h);✅ 使用1h 是 1m 的整数倍
SELECT COUNT(*), MIN(c1), SPREAD(c1) FROM stable INTERVAL(1h);❌ 不可用spread未定义(即使 spread 可由已定义的 MIN/MAX 推算,也不允许)
SELECT COUNT(*), MIN(c1) FROM stable INTERVAL(30s);❌ 不可用窗口不匹配,查询窗口需为创建窗口的整数倍
SELECT COUNT(*), MIN(c1) FROM stable where c2 > 0;❌ 不可用WHERE 含普通列过滤
SELECT COUNT(*) FROM stable GROUP BY c2;❌ 不可用GROUP BY 含普通列
SELECT MIN(c3), MIN(c2) FROM stable INTERVAL(1m);❌ 不可用c2未在 tsma1 中定义

递归 TSMA 的查询效果

基于 tsma1 创建递归 TSMA:

CREATE RECURSIVE TSMA tsma2 on tsma1 INTERVAL(1h);
  • SELECT COUNT(*), SUM(c1) FROM stable;—— 使用 tsma2(窗口更大优先);
  • SELECT COUNT(*), AVG(c1) FROM stable GROUP/PARTITION BY tbname, tag1, tag2;—— 使用 tsma2;
  • SELECT COUNT(*), MIN(c1) FROM stable INTERVAL(2h);—— 使用 tsma2(2h 是 1h 的整数倍);
  • SELECT COUNT(*), MIN(c1) FROM stable WHERE ts < '2023-01-01 10:10:10' INTERVAL(30m);—— 使用 tsma1(时间条件只作用于主键时间列 ts,30m 窗口匹配 1m 的 tsma1);
  • SELECT COUNT(*), MIN(c1) + MIN(c3) FROM stable INTERVAL(30m);—— 使用 tsma1(30m 不能整除 1h,但能整除 1m);
  • SELECT COUNT(*), MIN(c1) FROM stable INTERVAL(1h) SLIDING(30m);—— 使用 tsma1(SLIDING(30m) 无法被 1h 整除,只能匹配 1m 窗口);
  • SELECT COUNT(*), MIN(c1), SPREAD(c1) FROM stable INTERVAL(1h);—— 不可用(spread 未定义);
  • SELECT COUNT(*), MIN(c1) FROM stable INTERVAL(30s);—— 不可用(窗口不匹配);
  • SELECT COUNT(*), MIN(c1) FROM stable where c2 > 0;—— 不可用(普通列过滤)。

查询限制(querySmaOptimize = 1 时)

querySmaOptimize1且 SQL 中没有skip_tsma()hint 时,以下场景无法使用 TSMA:

  1. TSMA 中定义的聚合函数未覆盖当前查询的函数列表;
  2. INTERVAL窗口,或查询窗口大小(含INTERVAL, SLIDING, OFFSET不是定义窗口的整数倍。例如定义窗口为 2m,查询使用 5 分钟窗口则无法命中,但若存在 1m 窗口则可以使用;
  3. WHERE条件中包含任何普通列(非主键时间列)的过滤;
  4. PARTITIONGROUP BY中包含任何普通列或其表达式;
  5. 存在其他更快的优化逻辑可先执行,例如 last 缓存优化。执行顺序为先尝试 last 优化,last 无法进行时再判断能否使用 TSMA 优化;
  6. 当前 TSMA 的计算进度延迟超过maxTsmaCalcDelay参数阈值。

对原表的操作限制

创建 TSMA 后,对原超表进行以下操作会受到限制:

  • 删表:必须先删除该表上的全部 TSMA,才能删除表;
  • 标签列:原表的所有标签列不能被删除,子表的标签列名与标签值也不能被修改;删除标签列前必须先删除 TSMA;
  • 数据列:被某个 TSMA 使用到的列不能被删除,必须先删除 TSMA。新增列不受影响,但新列不会自动加入任何已有 TSMA——若需对新列计算,必须另行创建 TSMA。

查看 TSMA

SHOW [db_name.]TSMAS; SELECT * FROM information_schema.ins_tsma;

两种方式均可查看 TSMA 定义。需要注意:如果创建时指定的函数数量较多且列名较长,函数列表的展示可能被截断(当前支持最大输出 256KB)。

总结与最佳实践建议

综合文档与源码实现,使用 TSMA 加速长时间范围聚合查询的关键要点可归纳为:

  1. 按查询模式设计窗口:频繁执行无窗口聚合查询时,优先创建大窗口 TSMA;频繁执行INTERVAL/SLIDING窗口查询时,要让查询窗口、offset、sliding 尽量成为 TSMA 窗口的整数倍,并用递归 TSMA 构建「1m → 1h → 1d」式的多级窗口体系,让优化器始终有最合适的窗口可用;
  2. 函数列表宁全勿滥:函数列表决定可被优化的查询集合,spread、多列组合等未定义的函数会直接导致整个查询退回原始数据;同时受列数上限与行宽上限约束,常用函数可拆分到多个 TSMA;
  3. 关注数据一致性语义:TSMA 是异步流式计算结果,只保证最终一致性。对实时性敏感或涉及历史窗口数据更新的场景,应使用/*+ skip_tsma() */hint 或设置querySmaOptimize = 0,并合理配置maxTsmaCalcDelaytsmaDataDeleteMark
  4. 遵守运维顺序:删除表、标签列或被 TSMA 使用的列之前,必须先删除对应 TSMA;删除递归 TSMA 必须先于其基础 TSMA。

通过上述设计,TSMA 可以在天、月、年级别的时间范围内,让聚合查询直接命中预计算结果,显著减少原始数据扫描量,是 TDengine 上长周期统计分析类查询的关键性能优化手段。

【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 8:36:05

GCC 12.2.0 源码编译安装实战与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 8:35:54

Linux驱动面试真题背后的产线故障与源码级调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 8:34:38

数据库fetchsize参数详解:平衡网络与内存的查询性能调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 8:33:29

Triton 安装指南:从 pip 二进制包到源码编译与自定义 LLVM 构建

Triton 安装指南&#xff1a;从 pip 二进制包到源码编译与自定义 LLVM 构建 【免费下载链接】triton Development repository for the Triton language and compiler 项目地址: https://gitcode.com/GitHub_Trending/tri/triton 本篇技术指南面向所有想在本地搭建 Trito…

作者头像 李华
网站建设 2026/9/13 8:32:58

STM32+FreeRTOS智能安防系统实战:从传感器采集到云平台报警链路设计

简介&#xff1a;基于STM32F103和FreeRTOS&#xff0c;集成OneNET云平台与ESP8266 Wi-Fi模块的嵌入式安防系统项目源码&#xff0c;适合嵌入式开发者、物联网学习者以及准备电子竞赛或课程设计的学生。项目覆盖从外设驱动到云平台通信的完整链路&#xff0c;包含ADC、定时器、L…

作者头像 李华
网站建设 2026/9/13 8:32:31

贝尔数 Bell Numbers:OI 中的集合划分计数与高效计算

贝尔数 Bell Numbers&#xff1a;OI 中的集合划分计数与高效计算 【免费下载链接】OI-wiki :star2: Wiki of OI / ICPC for everyone. &#xff08;某大型游戏线上攻略&#xff0c;内含炫酷算术魔法&#xff09; 项目地址: https://gitcode.com/GitHub_Trending/oi/OI-wiki …

作者头像 李华