第1章:你不知道的TDEngine窗口查询——开局就不简单

先别急着翻白眼,提到时间窗口查询,可能你脑子里立马浮现的就是那些常规套路:GROUP BY time_intervalFIRST()LAST(),再加上点AVG()MAX(),一锅端。

可是,如果你用TDEngine还只是停留在这些层面,那说实话——你用的是一半的TDEngine,甚至不及格。

今天我们就不讲那些你能从官网文档抄到的东西,而是来把TDEngine时间窗口查询这块,彻底挖一挖,翻一翻,不光看它怎么用,还得琢磨出怎么用得漂亮。

1.1 时间窗口的本质:不是GROUP而是TIME ALIGN

很多人误以为TDEngine的窗口查询只是SQL里GROUP BY的变种。错了,TDEngine的窗口查询背后其实是一个时间对齐模型,它会根据你指定的窗口步长、起点,对原始数据进行自动分桶。

举个简单例子:

SELECT COUNT(*) FROM temperature_table INTERVAL(10m);

你以为只是10分钟分组?不对,其实它在做的是:从UNIX EPOCH(1970年1月1日)或你的查询起点,每隔10分钟生成一个桶,再把每个数据点丢到对应桶里。想清楚这一点,很多问题自然就通透了。

1.2 窗口查询的完整语法骨架

我们要玩得溜,就得先掌握TDEngine窗口查询的完整句式结构。

SELECT [agg_funcs] FROM [stable/table] 
[WHERE condition]
INTERVAL(step_time) 
[SLIDING(step)]
[FILL(null | previous | 0)]
[ALIGN(starting_point)]
[GROUP BY tags]

这几个关键词你得明白它们的作用和组合方式,不然后面进阶玩法全玩不转。

  • INTERVAL(x):这个是窗口的宽度。

  • SLIDING(x):这个是滑动步长,默认跟INTERVAL一样,但你可以自定义成任意值,实现滑窗效果。

  • FILL:控制窗口里没数据的桶的填充值。

  • ALIGN:决定窗口从哪一刻开始划分。

现在我们直接从实战讲起,不空讲任何一个参数。

1.3 INTERVAL + SLIDING:滑窗玩法的关键

实例:按15分钟聚合,每5分钟滚动一次
SELECT AVG(temperature) 
FROM temperature_table 
WHERE ts >= now - 2h
INTERVAL(15m) SLIDING(5m);

这就是一个滑动窗口聚合查询,每个15分钟窗口会向前滑动5分钟生成一个新的结果。

也就是说,如果你的时间范围是2小时,那你将会得到:

  • 00:00 ~ 00:15

  • 00:05 ~ 00:20

  • 00:10 ~ 00:25 ...

这种玩法特别适合用于实时数据的趋势监测,尤其是在工业设备监控和金融K线生成中非常常见。

再来一个带点刺激的:

实例:动态监控平均温度变化率
SELECT (AVG(temperature) - LAG(AVG(temperature))) / SLIDING(5m) AS rate 
FROM temperature_table 
WHERE ts >= now - 1h
INTERVAL(15m) SLIDING(5m);

这段SQL可不常规,它是通过窗口差值做了一个时间上的衍生指标计算,常用于预测模型特征提取

注:目前TDEngine原生还不支持LAG这种窗口函数,这种写法需要通过客户端拆解计算实现。

第2章:别让“缺口”搞乱你的窗口——深入FILL与ALIGN的奥秘

TDEngine 的窗口查询,很多时候看起来没毛病,可结果就偏偏不对,这种情况十有八九都是 FILLALIGN 在搞事情。

我们一个个来抠细节。

2.1 FILL:给数据“打补丁”的神技能

默认情况下,如果某个窗口内没有任何数据点,那这一段时间的桶压根就不会出现在查询结果里。

但是你做可视化,或做统计模型训练时,突然断档,不仅图表变形、聚合数出错,严重点可能直接导致你的报警系统漏报或者误报。

所以,FILL这个参数你必须会用

FILL(null)

最简单粗暴的做法——什么都不补,窗口没数据就让它空着:

SELECT AVG(temperature) 
FROM temperature_table 
WHERE ts >= now - 1h
INTERVAL(10m) FILL(null);

结果中,你会看到有些10分钟时间段是空的。这个策略适合数据科学用途,但不适合报表可视化。

FILL(0) 或 FILL(previous)
  • FILL(0):补零,这种方式简单粗暴,适合电量统计、总线监控这类场景。

  • FILL(previous):拿前一个非空值来填补空位,适合做趋势对比、图表平滑处理。

实战案例:气压监测不中断
SELECT MAX(pressure) 
FROM station_data 
WHERE ts >= now - 1d
INTERVAL(30m) FILL(previous);

用这个你就可以确保图表上的曲线不会有断点。

⚠️注意:FILL(previous) 只在时间序列有“连续性预期”的情况下使用,别滥用。

2.2 ALIGN:对齐时间才是硬道理

你是不是遇到过这种怪事:你明明查的是now - 1h的数据,结果窗口的起点却是一些奇怪的时间,比如13:02:30

问题就出在ALIGN参数没设置。

ALIGN的作用

ALIGN(ts) 指定你的窗口应该从哪个时间点开始对齐切分。

SELECT COUNT(*) 
FROM login_table 
WHERE ts >= now - 6h
INTERVAL(1h) ALIGN(00:00);

上面的语句表示:窗口从每天的00:00点开始切分,每1小时一个桶

这样你在做日报时,结果就非常整齐划一。

使用ALIGN(now)实时对齐

你也可以让窗口以当前时间对齐:

SELECT SUM(energy) 
FROM device_power 
WHERE ts >= now - 4h
INTERVAL(1h) ALIGN(now);

这就意味着每次查询结果的窗口都会动态对齐到此刻。

第3章:超级表的窗口聚合——你以为的简单,其实暗藏玄机

讲真,TDEngine的“超级表(Super Table)”机制可以说是它最酷也最容易踩坑的一部分。尤其是当你试图用窗口聚合搞多个子表汇总时,如果你不留个心眼,结果就会比你想象的还乱——而且还是悄悄地乱

3.1 什么是超级表的窗口聚合?

场景设定:假如你有一张超级表 meters,它包含了成百上千个子表(比如一栋楼的不同电表):

CREATE STABLE meters (ts TIMESTAMP, voltage FLOAT, current FLOAT) TAGS (location BINARY(64), phase INT);

然后你基于这张超级表创建了几千个表:

CREATE TABLE meter001 USING meters TAGS ("A栋1单元", 1);
CREATE TABLE meter002 USING meters TAGS ("A栋2单元", 1);
...

现在你想统计这栋楼里每个相位(phase)的平均电压变化趋势,每15分钟为一个窗口,每小时滚动一次。

很多人上来就写:

SELECT AVG(voltage) 
FROM meters 
WHERE ts > now - 1d 
INTERVAL(15m) SLIDING(1h) 
GROUP BY phase;

然后你发现结果“怪怪的”:

  • 有的时间段缺数据;

  • 某些phase没出现在结果里;

  • 数据数量不稳定。

问题在哪?是数据分布不均、窗口未对齐、子表未完整聚合,等等统统叠加。

3.2 拆分对齐:稳准狠的三步法

要想搞定超级表聚合查询,建议按以下思路来分步处理

第一步:确认数据分布是否均衡

你得先了解每个子表是否在你关注的时间段内都有数据。

SELECT tbname, COUNT(*) 
FROM meters 
WHERE ts >= now - 1d 
GROUP BY tbname;

如果你看到很多是0,那说明不是查询语句的问题,而是压根没数据。

第二步:强制时间对齐 + 填补空缺

这是窗口查询里必须加的参数组合:

SELECT AVG(voltage) 
FROM meters 
WHERE ts >= now - 1d 
INTERVAL(15m) SLIDING(1h) 
FILL(previous) ALIGN(00:00) 
GROUP BY phase;

有了这个组合,结果才是完整、有规律的窗口段——对BI系统来说简直不要太重要。

第三步:GROUP BY顺序 VS TAG使用

如果你 GROUP BY 的字段不是 TAG,而是某个字段值,那在超级表场景下可能会出错。

错误示范:

-- voltage不是tag,这样写在超级表上毫无意义
SELECT AVG(voltage) FROM meters INTERVAL(15m) GROUP BY voltage;

正确做法要结合超级表的 TAG 字段:

SELECT AVG(voltage) 
FROM meters 
WHERE ts >= now - 12h 
INTERVAL(15m) 
GROUP BY location;

 一句话:TDEngine 的 GROUP BY 只能对 TAG 字段起到分组汇总作用!

小贴士:如果你对查询结果不放心,建议输出 tbname 一列,对比一下具体是哪些子表返回了数据。

SELECT tbname, AVG(current) 
FROM meters 
WHERE ts >= now - 3h 
INTERVAL(10m) 
GROUP BY tbname;

这个技巧在调试复杂聚合时非常有用,别忽视它!

第4章:窗口滑动别只会“匀速跑”——不规则窗口 + 嵌套窗口查询解法

时间窗口查询的“滑动”功能(SLIDING)非常强大,但很多时候我们用得还不够花——绝大多数人都在用等间距滑窗,比如每小时滑动一次、每五分钟滑动一次。

可现实数据分析可没那么规整,有时候你就得:

  • 定义“跳跃式窗口”:窗口本身间隔固定,但不连续滚动;

  • 在同一查询中对多个时间粒度做对比(比如小时内再聚合分钟趋势);

  • 甚至在子查询中对滑动窗口进行再聚合,这个时候你需要嵌套窗口查询

我们下面一个个来拆。

4.1 不规则滑动窗口:跳着来照样聚合

场景:每小时数据只取前15分钟做统计

你希望每小时内只分析第一个15分钟窗口数据,后面的不看。

你以为只能用 INTERVAL(1h)?其实用 SLIDING 更灵活:

SELECT AVG(temperature) 
FROM temperature_table 
WHERE ts >= now - 6h 
INTERVAL(15m) SLIDING(1h);

别小看这个用法,它其实实现的是“每小时一个窗口,但窗口长度只有15分钟”,跳窗分析就这么玩。

场景升级:仅分析奇数小时数据

这种需求就得靠业务逻辑去组合:

SELECT * FROM (SELECT AVG(voltage) AS v, ts FROM power_data WHERE HOUR(ts) % 2 = 1 INTERVAL(30m) SLIDING(1h)
) t;

注意这里其实是靠 SQL 中的时间函数加窗口语法联合筛选达成。

4.2 窗口 + 窗口?可以!嵌套查询了解下

TDEngine 虽然目前对窗口函数嵌套支持有限,但我们可以通过子查询的方式实现“窗口套窗口”的效果。

案例:先按10分钟滑动平均,再按小时汇总滑动平均走势
SELECT AVG(avg_temp) 
FROM (SELECT AVG(temperature) AS avg_temp FROM sensors WHERE ts >= now - 2h INTERVAL(10m) SLIDING(5m)
) t 
INTERVAL(1h);

这个操作在数据科学和模型训练中非常常用,尤其是在构建多级平滑曲线、分层特征提取时效果拔群。

⚠️ 注意:当前 TDEngine 在子查询中不能嵌套 GROUP BY tags,需要按单表/结构规避。

4.3 JOIN + 窗口:动态对齐不同类型数据

有没有遇到过这种情况:你有两个超级表,一个记录设备状态(开关变化),一个记录温度,你想知道“每次设备开的时候,接下来的5分钟内温度均值”?

这时候我们可以用 JOIN + 窗口来干:

SELECT s.ts, d.status, AVG(s.temperature) 
FROM temperature_table s 
JOIN status_table d ON s.ts BETWEEN d.ts AND d.ts + 5m
WHERE d.status = 1
GROUP BY d.ts;

或者你用窗口套件配合写法:

SELECT AVG(temp) 
FROM (SELECT s.temperature AS temp, d.ts AS anchor FROM s JOIN d ON s.ts BETWEEN d.ts AND d.ts + 5m WHERE d.status = 1
) t 
INTERVAL(5m) ALIGN(anchor);

是不是已经闻到高级数据处理的味道了?

第6章:性能,才是生产级窗口查询的底线

很多人写窗口查询时从不关心性能,直到查询开始“转圈圈”,然后盯着后台日志一脸懵逼。其实,TDEngine 的窗口查询本身是非常高效的,但前提是你避开以下几个常见陷阱。

这一章,我们就来拆开这些“隐形炸弹”,再教你几招能让你的窗口查询飞起来的优化套路。

6.1 避雷第一条:INTERVAL步长别太小!

你想象一下,如果你执行的是:

SELECT AVG(temp) 
FROM data 
WHERE ts >= now - 1h 
INTERVAL(1s);

意味着什么?意味着 TDEngine 要在一小时内切出 3600个桶

这不是查询,这是压力测试……

建议:INTERVAL 不要低于5s,常用为 10s ~ 1min

如果你必须这么小的粒度,那就考虑先用大粒度做聚合,做成中间表缓存再查。

6.2 SLIDING步长≠精度

很多同学以为“我把 SLIDING 改成 1s,就能实时得出结果”,这是错的。

SLIDING 控制的是窗口生成频率,不是数据采样频率。

你该关心的是:有没有数据进入这个窗口,而不是滑了多少次。

正确理解这个参数,有助于你把查询控制在“刚刚好”的复杂度上。

6.3 GROUP BY TAG = 分片执行!

TDEngine 的超级表分组其实是一种“分片执行”。

如果你写了:

SELECT AVG(v) FROM stable_name INTERVAL(1m) GROUP BY device_id;

那系统会为每个 device_id 子表执行一次完整查询,再汇总。

所以如果你有 10w 个设备,恭喜你,触发了 10w 次执行路径。

解决方案:分批查询、分页聚合、或建立预聚合表(物化视图)

6.4 LIMIT和TOPN一定要加

执行窗口查询的时候,如果你只是临时查数据,那请加上 LIMIT,比如:

SELECT AVG(x) FROM y INTERVAL(10m) LIMIT 100;

或者你只关心某几个设备的:

SELECT TOP(10) device_id, AVG(x) FROM y GROUP BY device_id;

没有 LIMIT = 默认全表聚合 = 查询崩溃边缘试探。

6.5 提前准备的数据结构优化

你别以为 SQL 优化就够了,其实 TDEngine 在建表时就能埋下优化伏笔:

  • 建表时设置合适的 COMP 压缩算法,对时序聚合性能有帮助;

  • 使用合理的 TAG 作为查询条件,可以极大减少 I/O 扫描成本;

  • 利用 TTL 机制清理旧数据,避免“历史包袱”拖慢全局。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/87424.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87424.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/87424.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day50 预训练模型+CBAM模块

目录 一、resnet结构解析 二、CBAM放置位置的思考 三、针对预训练模型的训练策略 a.差异化学习率 b.三阶段式解冻与微调 (Progressive Unfreezing) 四、尝试对vgg16cbam进行微调策略 是否可以对于预训练模型增加模块来优化其效果,这里会遇到一个问题&#xff…

快速说一下TDD BDD DDD

基本概念 TDD(测试驱动开发)、BDD(行为驱动开发)和 DDD(领域驱动设计)是软件开发领域中几个重要的概念,它们各自有着独特的侧重点与应用场景,以下为你详细介绍: 测试驱…

浅析基于深度学习算法的英文OCR技术工作原理及其应用场景

在数字化信息飞速发展的当下,大量的文本信息以各种形式存在,从传统的纸质文档到电子图片中的文字内容。如何高效地将这些非结构化的文本转化为计算机能够理解和处理的格式,成为了提高信息处理效率的关键。英文 OCR(Optical Charac…

AI时代SEO关键词策略

内容概要 在人工智能(AI)驱动的新时代,搜索引擎优化(SEO)关键词策略正迎来颠覆性变革。本篇文章将系统解析AI技术如何重塑关键词研究、内容优化及流量提升的全过程,帮助企业实现高效可持续的在线曝光。通过…

免费一键自动化申请、续期、部署、监控所有 SSL/TLS 证书,ALLinSSL开源免费的 SSL 证书自动化管理平台

目录 一、前言二、ALLinSSL 简介亮点核心功能 三、操作步骤部署安装授权DNS服务商授权你的主机服务器自动化部署ssl测试自动申请ssl证书 一、前言 SSL证书是每个网站必备的,但是现在的免费的ssl证书有效期是3个月,以后CA/B Forum 调整 SSL 证书最长有效期…

如何高效清理C盘、释放存储空间,让电脑不再卡顿。

以下是针对Windows系统的C盘深度清理全攻略,包含系统级优化和进阶操作,可释放30%-70%的冗余空间: 一、系统自带工具快速清理(5分钟见效) 磁盘清理工具 按WinR → 输入cleanmgr → 选择C盘重点勾选: ✅ Wind…

AI 如何批量提取 Word 表格中的字段数据到 Excel 中?

在日常工作中,我们经常会接触到大量 Word 表格——学生登记表、客户信息表、报名信息表……这些表格数据往往格式不一,但有一个共同的需求: 从中提取出“字段-值”结构,统一导入 Excel,方便后续分析处理。 传统手工操作…

github代码中遇到的问题-解决方案

下面内容介绍的是我个人在复现github代码遇到的一些问题,如果也可以帮到你,请点个关注吧~ 1.我的项目位置在D盘,但是为什么下面终端的位置在E盘 -》cd /d D:\Users\xxxx(后面的xxxx是你具体的文档位置) 2.怎么知道我…

使用Visual Studio 2022创建CUDA编程项目

要在 Visual Studio 2022 中开发 CUDA 程序,需要进行环境配置并了解基本开发流程。以下是详细步骤: 环境准备 安装 Visual Studio 2022 下载并安装 Visual Studio 2022(社区版或专业版均可)。安装时勾选 “使用 C++ 的桌面开发” 工作负载。确保安装 “C++ CMake 工具” …

Java测试题一

1.基本数据类型有哪些? 基本数据类型有8个:整数:byte、int、long、short。 浮点型:float、double。 布尔型boolean。 字符型:char 2.下列代码的输出是什么?为什么? public static void ma…

使用 Flask 构建基于 Dify 的企业资金投向与客户分类评估系统

使用 Flask 构建基于 Dify 的企业资金投向与客户分类评估系统 前言一、🧩 技术栈二、📦 项目结构概览三、 🔧 核心功能模块说明1 配置参数2 请求封装函数✅ 功能说明: 3 Prompt 构造函数4 Flask 路由定义🏠 首页路由 /…

深入解析 AAC AudioSpecificConfig 在 RTSP/RTMP 播放器中的核心作用

在音视频开发中,“能播”往往只是第一步,**“能正确、稳定、高质量地播”**才是衡量一款播放器成熟度的真正标准。尤其是在面对 AAC 音频流时,很多开发者容易忽视一个极其关键但看似微小的配置段 —— AAC Audio Specific Config(…

Redis在项目中的使用

Redis(Remote Dictionary Server,远程字典服务)是一个开源的键值存储系统,通常用作数据库、缓存或消息传递系统。在项目中,Redis 可以发挥多种作用,以下是一些常见的使用场景: 1. 缓存 减少数据…

使用 collected 向 TDengine 写入数据

collectd 是一个用来收集系统性能的守护进程。collectd 提供各种存储方式来存储不同值的机制。它会在系统运行和存储信息时周期性的统计系统的相关统计信息。利用这些信息有助于查找当前系统性能瓶颈和预测系统未来的负载等。 只需要将 collectd 的配置指向运行 taosAdapter 的…

greeenplum7.2几个问题的解决方案

问题1systemd-modules-load.service报错 systemd-modules-load.service: 这个服务负责加载内核模块。在容器环境下,除非特别需要,否则通常不需要加载额外的内核模块。 auditd.service: 审计守护进程(Audit Daemon),用…

AppInventor2 MQTT教程之 - EasyIoT 平台接入

之前发过一次MQTT超级入门教程,使用巴法云作为测试平台,详见: App Inventor 2 MQTT拓展入门(保姆级教程) 这里介绍MQTT接入另一家IoT平台:EasyIoT。 网址:https://iot.dfrobot.com.cn/&#…

打造企业级 AI 能力中台:Prompt DSL 管理与多模型前端架构

关键点 AI 能力中台:企业级 AI 能力中台整合多模型接入、Prompt 管理和组件复用,为跨团队协作提供高效前端架构。Prompt DSL 管理:通过领域特定语言(DSL)标准化 Prompt 设计,支持动态配置和复用。多模型统…

NumPy 安装使用教程

一、NumPy 简介 NumPy(Numerical Python)是 Python 中用于进行科学计算的基础库之一。它提供了高效的多维数组对象 ndarray,以及用于数组操作、线性代数、傅里叶变换、随机数等丰富的函数。 二、安装 NumPy 2.1 使用 pip 安装(推…

LeetCode Hot 100 哈希【Java和Golang解法】

1.两数之和 1.两数之和 Java解法 class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer, Integer> record new HashMap<>();for(int i 0; i < nums.length; i) {int temp target - nums[i];if (record.containsKey(temp)) {return n…

MySQL(108)如何进行分片合并?

分片合并&#xff08;Sharding Merge&#xff09;是指在分布式数据库系统中&#xff0c;将不同分片上的查询结果进行整合&#xff0c;以获得完整的查询结果。实现分片合并主要包括以下几个步骤&#xff1a; 查询所有相关分片&#xff1a;在所有相关分片上执行查询&#xff0c;…