完全指南:创建、查询优化与限制)
TDengine TSMA时间范围小型物化聚合完全指南创建、查询优化与限制【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine导读在 TDengine 中当历史数据量持续增长、查询时间跨度扩展到天、月甚至年级别时聚合查询需要扫描的原始数据块数量会急剧增加查询耗时随之上升。TSMATime-Range Small Materialized Aggregates时间范围小型物化聚合允许用户为超表supertable或普通表basic table指定固定时间窗口将窗口内的聚合结果预先计算并存储使后续查询直接读取预计算结果而无需扫描原始数据。本文基于 01-tsma.md 文档结合 TDengine 开源仓库源码系统讲解 TSMA 的创建语法、支持的聚合函数、查询匹配规则、使用限制与相关配置参数帮助你在实际业务中正确设计与使用 TSMA 加速长时间范围的聚合查询。TSMA 是什么从块内 SMA 到时间窗口物化TDengine 的数据存储按数据块block组织每个数据块内部本身就携带 SMASmall 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)来表达“统计记录数”的语义。删除 TSMADROP TSMA [db_name.]tsma_name;若待删除的 TSMA 被其他 TSMA 作为基础存在递归 TSMA 依赖删除操作会报错Invalid drop base tsma, drop recursive tsma first。因此必须先删除所有基于它创建的递归 TSMA再删除基础 TSMA。DROP TSMA与CREATE TSMA、SHOW CREATE TSMA一起被纳入权限体系管理见 source/common/src/tpriv.c#L231-L234其中DROP TSMA对应PRIV_CM_DROP权限。TSMA 计算原理TSMA 的计算通过流式计算完成是一个后台异步过程计算结果不保证实时精确但能保证最终正确性ultimate correctness当原表的某个子表没有数据时可能不会创建对应的输出子表。因此即使配置了countAlwaysReturnValuecount查询也不会返回该表的计数结果当存在大量历史数据时创建 TSMA 后流式计算会先回算历史数据此期间新建的 TSMA 不会被查询使用数据发生更新、删除或数据过期时受影响的数据会被自动重新计算重算期间TSMA 查询结果不保证实时精确。若希望查询实时数据有两种途径绕过 TSMA在 SQL 中增加 Hint/* skip_tsma() */将客户端参数querySmaOptimize设置为0。相关配置参数服务端参数maxTsmaNum位置taosd 服务端配置见 taosd 配置参数默认值10取值范围[0, 10]作用限制整个集群内可创建的 TSMA 总数。客户端参数以下参数均在 taosc 客户端配置中详见 taosc 查询相关配置参数说明默认值取值范围querySmaOptimize查询时是否使用 TSMA1使用预计算结果0查询原始数据00/1maxTsmaCalcDelay单位秒控制可接受的 TSMA 计算延迟。当 TSMA 计算进度与最新时间之差在该值范围内时使用该 TSMA否则不使用60010 分钟最小 60010 分钟最大 864001 天tsmaDataDeleteMark单位毫秒与流式计算参数deleteMark一致控制流式计算中中间结果的保留时长1d86400000 ms最小1h3600000 mstsmaDataDeleteMark的语义需要特别关注距离最后一条数据超过该时长的历史窗口不会保留中间结果。如果这些历史窗口中的数据被修改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。在窗口查询中INTERVAL、OFFSET、SLIDING三个值都会影响可用 TSMA 窗口大小——可被整除的窗口指 TSMA 窗口大小能被查询语句的INTERVAL, OFFSET, SLIDING整除。因此若窗口查询使用频繁创建 TSMA 时应综合考虑常用查询窗口、offset 与 sliding 的大小。示例 1创建了5m和10m两个窗口的 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 创建递归 TSMACREATE 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;—— 使用 tsma2SELECT COUNT(*), MIN(c1) FROM stable INTERVAL(2h);—— 使用 tsma22h 是 1h 的整数倍SELECT COUNT(*), MIN(c1) FROM stable WHERE ts 2023-01-01 10:10:10 INTERVAL(30m);—— 使用 tsma1时间条件只作用于主键时间列 ts30m 窗口匹配 1m 的 tsma1SELECT COUNT(*), MIN(c1) MIN(c3) FROM stable INTERVAL(30m);—— 使用 tsma130m 不能整除 1h但能整除 1mSELECT COUNT(*), MIN(c1) FROM stable INTERVAL(1h) SLIDING(30m);—— 使用 tsma1SLIDING(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 时当querySmaOptimize为1且 SQL 中没有skip_tsma()hint 时以下场景无法使用 TSMATSMA 中定义的聚合函数未覆盖当前查询的函数列表非INTERVAL窗口或查询窗口大小含INTERVAL, SLIDING, OFFSET不是定义窗口的整数倍。例如定义窗口为 2m查询使用 5 分钟窗口则无法命中但若存在 1m 窗口则可以使用WHERE条件中包含任何普通列非主键时间列的过滤PARTITION或GROUP BY中包含任何普通列或其表达式存在其他更快的优化逻辑可先执行例如 last 缓存优化。执行顺序为先尝试 last 优化last 无法进行时再判断能否使用 TSMA 优化当前 TSMA 的计算进度延迟超过maxTsmaCalcDelay参数阈值。对原表的操作限制创建 TSMA 后对原超表进行以下操作会受到限制删表必须先删除该表上的全部 TSMA才能删除表标签列原表的所有标签列不能被删除子表的标签列名与标签值也不能被修改删除标签列前必须先删除 TSMA数据列被某个 TSMA 使用到的列不能被删除必须先删除 TSMA。新增列不受影响但新列不会自动加入任何已有 TSMA——若需对新列计算必须另行创建 TSMA。查看 TSMASHOW [db_name.]TSMAS; SELECT * FROM information_schema.ins_tsma;两种方式均可查看 TSMA 定义。需要注意如果创建时指定的函数数量较多且列名较长函数列表的展示可能被截断当前支持最大输出 256KB。总结与最佳实践建议综合文档与源码实现使用 TSMA 加速长时间范围聚合查询的关键要点可归纳为按查询模式设计窗口频繁执行无窗口聚合查询时优先创建大窗口 TSMA频繁执行INTERVAL/SLIDING窗口查询时要让查询窗口、offset、sliding 尽量成为 TSMA 窗口的整数倍并用递归 TSMA 构建「1m → 1h → 1d」式的多级窗口体系让优化器始终有最合适的窗口可用函数列表宁全勿滥函数列表决定可被优化的查询集合spread、多列组合等未定义的函数会直接导致整个查询退回原始数据同时受列数上限与行宽上限约束常用函数可拆分到多个 TSMA关注数据一致性语义TSMA 是异步流式计算结果只保证最终一致性。对实时性敏感或涉及历史窗口数据更新的场景应使用/* skip_tsma() */hint 或设置querySmaOptimize 0并合理配置maxTsmaCalcDelay与tsmaDataDeleteMark遵守运维顺序删除表、标签列或被 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),仅供参考