Apache IoTDB 深度解析时序数据聚合的 GROUP BY 与 HAVING 子句
时序数据聚合是工业物联网数据分析的核心。Apache IoTDB 提供 GROUP BY 子句支持时间窗口、设备层级及标签多维分组,结合 HAVING 子句实现聚合结果过滤。文章详解了路径层级、标签组合及时间区间混合聚合的语法与场景,并通过智慧交通案例展示协同查询方案,助力提升查询效率与业务洞察能力。

时序数据聚合是工业物联网数据分析的核心。Apache IoTDB 提供 GROUP BY 子句支持时间窗口、设备层级及标签多维分组,结合 HAVING 子句实现聚合结果过滤。文章详解了路径层级、标签组合及时间区间混合聚合的语法与场景,并通过智慧交通案例展示协同查询方案,助力提升查询效率与业务洞察能力。

在工业物联网场景中,某设备监控系统每秒产生超过 2 万条包含温度、压力、振动幅度的多维时序数据。若直接存储原始数据,单日存储量将突破 200GB。通过 IoTDB 的分组聚合(GROUP BY)与聚合结果过滤(HAVING)子句的协同使用,保证分析结果的精准性。
Apache IoTDB 时序数据库【系列篇章】:
| No. | 文章地址 |
|---|---|
| 1 | Apache IoTDB(1):时序数据库介绍与单机版安装部署指南 |
| 2 | Apache IoTDB(2):时序数据库 IoTDB 集群安装部署的技术优势与适用场景分析 |
| 3 | Apache IoTDB(3):时序数据库 IoTDB Docker 部署从单机到集群的全场景部署与实践指南 |
| 4 | Apache IoTDB(4):深度解析时序数据库 IoTDB 在 Kubernetes 集群中的部署与实践指南 |
| 5 | Apache IoTDB(5):深度解析时序数据库 IoTDB 中 AINode 工具的部署与实践 |
| 6 | Apache IoTDB(6):深入解析数据库管理操作——增删改查与异构数据库实战指南 |
| 7 | Apache IoTDB(7):设备模板管理——工业物联网元数据标准化的破局之道 |
| 8 | Apache IoTDB(8):时间序列管理——从创建到分析的实战指南 |
| 9 | Apache IoTDB(9):数据库操作——数据写入从 CLI 到集群部署的六种实战 |
| 10 | Apache IoTDB(10):数据库操作——从查询到优化的全链路实践指南 |
| 11 | Apache IoTDB(11):分段聚合深度解析——从原理到实战的完整指南 |
本文将从案例,系统剖析这两个子句的协同工作机制。不同于传统数据库的聚合操作,IoTDB 针对时序数据的特性进行了深度优化,支持时间窗口、设备层级、标签等多维分组方式,并可通过 HAVING 子句实现聚合结果的精准过滤。
在时间序列层级结构中,路径层级分组聚合查询用于对某一层级下同名的序列进行聚合查询。
使用 GROUP BY LEVEL = INT 来指定需要聚合的层级,并约定 ROOT 为第 0 层。若统计 "root.ln" 下所有序列则需指定 level 为 1。路径层次分组聚合查询支持使用所有内置聚合函数。对于 sum, avg, min_value, max_value, extreme 五种聚合函数,需保证所有聚合的时间序列数据类型相同。其他聚合函数没有此限制。
示例 1:不同 database 下均存在名为 status 的序列,如 "root.ln.wf01.wt01.status", "root.ln.wf02.wt02.status", 以及 "root.sgcc.wf03.wt01.status", 如果需要统计不同 database 下 status 序列的数据点个数,使用以下查询:
SELECT COUNT(status) FROM root.** GROUP BY LEVEL = 1
结果展示统计信息。
示例 2:统计不同设备下 status 序列的数据点个数,可以规定 level = 3
SELECT COUNT(status) FROM root.** GROUP BY LEVEL = 3
注意:这时会将 database ln 和 sgcc 下名为 wt01 的设备视为同名设备聚合在一起。
示例 3:统计不同 database 下的不同设备中 status 序列的数据点个数
SELECT COUNT(status) FROM root.** GROUP BY LEVEL = 1, 3
示例 4:查询所有序列下温度传感器 temperature 的最大值,可以使用下列查询语句:
SELECT MAX_VALUE(temperature) FROM root.** GROUP BY LEVEL = 0
示例 5:上面的查询都是针对某一个传感器,特别地,如果想要查询某一层级下所有传感器拥有的总数据点数,则需要显式规定测点为 *
SELECT COUNT(*) FROM root.ln.** GROUP BY LEVEL = 2
通过定义 LEVEL 来统计指定层级下的数据点个数。
示例 1:统计降采样后的数据点个数
SELECT COUNT(status) FROM root.ln.wf01.wt01 GROUP BY ((2017-11-01T00:00:00,2017-11-07T23:00:00],1d), LEVEL=1;
示例 2:加上滑动 Step 的降采样后的结果也可以汇总
SELECT COUNT(status) FROM root.ln.wf01.wt01 GROUP BY ([2017-11-01 00:00:00,2017-11-07 23:00:00),3h,1d), LEVEL=1;
IoTDB 支持通过 GROUP BY TAGS 语句根据时间序列中定义的标签的键值做分组聚合查询。
我们先在 IoTDB 中写入如下示例数据,稍后会以这些数据为例介绍标签聚合查询。
这些是某工厂 factory1 在多个城市的多个车间的设备温度数据,时间范围为 [1000, 10000)。
时间序列路径中的设备一级是设备唯一标识。城市信息 city 和车间信息 workshop 则被建模在该设备时间序列的标签中。 其中,设备 d1、d2 在 Beijing 的 w1 车间,d3、d4 在 Beijing 的 w2 车间,d5、d6 在 Shanghai 的 w1 车间,d7 在 Shanghai 的 w2 车间。 d8 和 d9 设备目前处于调试阶段,还未被分配到具体的城市和车间,所以其相应的标签值为空值。
CREATE DATABASE root.factory1;
CREATE TIMESERIES root.factory1.d1.temperature WITH DATATYPE=FLOAT TAGS(city=Beijing, workshop=w1);
CREATE TIMESERIES root.factory1.d2.temperature WITH DATATYPE=FLOAT TAGS(city=Beijing, workshop=w1);
CREATE TIMESERIES root.factory1.d3.temperature WITH DATATYPE=FLOAT TAGS(city=Beijing, workshop=w2);
CREATE TIMESERIES root.factory1.d4.temperature WITH DATATYPE=FLOAT TAGS(city=Beijing, workshop=w2);
CREATE TIMESERIES root.factory1.d5.temperature WITH DATATYPE=FLOAT TAGS(city=Shanghai, workshop=w1);
CREATE TIMESERIES root.factory1.d6.temperature WITH DATATYPE=FLOAT TAGS(city=Shanghai, workshop=w1);
CREATE TIMESERIES root.factory1.d7.temperature WITH DATATYPE=FLOAT TAGS(city=Shanghai, workshop=w2);
CREATE TIMESERIES root.factory1.d8.temperature WITH DATATYPE=FLOAT;
CREATE TIMESERIES root.factory1.d9.temperature WITH DATATYPE;
root.factory1.d1(, temperature) (, ), (, ), (, ), (, );
root.factory1.d2(, temperature) (, ), (, ), (, ), (, );
root.factory1.d3(, temperature) (, ), (, ), (, ), (, );
root.factory1.d4(, temperature) (, ), (, ), (, );
root.factory1.d5(, temperature) (, ), (, );
root.factory1.d6(, temperature) (, ), (, ), (, ), (, );
root.factory1.d7(, temperature) (, ), (, ), (, ), (, );
root.factory1.d8(, temperature) (, ), (, ), (, ), (, );
root.factory1.d9(, temperature) (, ), (, );
统计该工厂每个地区的设备的温度的平均值,可以使用如下查询语句
SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city);
该查询会将具有同一个 city 标签值的时间序列的所有满足查询条件的点做平均值计算。
从结果集中可以看到,和分段聚合、按层次分组聚合相比,标签聚合的查询结果的不同点是:
除了基本的单标签聚合查询外,还可以按顺序指定多个标签进行聚合计算。
例如,统计每个城市的每个车间内设备的平均温度。但因为各个城市的车间名称有可能相同,所以不能直接按照 workshop 做标签聚合。必须要先按照城市,再按照车间处理。
SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city, workshop);
从结果集中可以看到,和单标签聚合相比,多标签聚合的查询结果会根据指定的标签顺序,输出相应标签的键值列。
按照时间区间聚合是时序数据库中最常用的查询需求之一。IoTDB 在基于时间区间的聚合基础上,支持进一步按照标签进行聚合查询。
例如,统计时间 [1000, 10000) 范围内,每个城市每个车间中的设备每 5 秒内的平均温度。
SELECT AVG(temperature) FROM root.factory1.** GROUP BY ([1000,10000),5s), TAGS(city, workshop);
和标签聚合相比,基于时间区间的标签聚合的查询会首先按照时间区间划定聚合范围,在时间区间内部再根据指定的标签顺序,进行相应数据的聚合计算。在输出的结果集中,会包含一列时间列,该时间列值的含义和时间区间聚合查询的相同。
如果想对聚合查询的结果进行过滤,可以在 GROUP BY 子句之后使用 HAVING 子句。
| 对比项 | WHERE 子句 | HAVING 子句 |
|---|---|---|
| 执行阶段 | 分组前执行(行级过滤) | 分组后执行(组级过滤) |
| 引用对象 | 原始列或常量 | 聚合函数结果 |
| 索引适用性 | 可利用 B+ 树索引加速 | 无法直接使用索引 |
| 典型场景 | 数据预筛选 | 聚合结果二次筛选 |
在工业质检场景中,通过 SELECT device_id, count(*) FROM production GROUP BY device_id HAVING count(*) > 1000 可快速定位产量异常设备。配合 WHERE 子句的 AND quality_status='failed' 实现缺陷设备的精准定位,使质检效率提升 50%。
下列使用方式是不正确的:
SELECT COUNT(s1) FROM root.** GROUP BY ([1,3),1ms) HAVING SUM(s1) > s1
SELECT COUNT(s1) FROM root.** GROUP BY ([1,3),1ms) HAVING s1 > 1
下列使用方式是不正确的:
SELECT COUNT(s1) FROM root.** GROUP BY ([1,3),1ms), LEVEL=1 HAVING SUM(d1.s1) > 1
SELECT COUNT(d1.s1) FROM root.** GROUP BY ([1,3),1ms), LEVEL=1 HAVING SUM(s1) > 1
SELECT COUNT(s1) FROM root.** GROUP BY ([1,11),2ms), LEVEL=1 HAVING COUNT(s2) > 2;
SELECT COUNT(s1), COUNT(s2) FROM root.** GROUP BY ([1,11),2ms) HAVING COUNT(s2) > 1 ALIGN BY DEVICE;
某智慧城市项目需要实现:
SELECT intersection_id, AVG(speed) AS avg_speed, COUNT(*) FILTER (WHERE status='congestion') AS congestion_count
FROM root.city.traffic
WHERE time>='2023-12-01 00:00:00' AND time<='2023-12-07 23:59:59'
GROUP BY TIME(5m), intersection_id
HAVING avg_speed < 30 AND congestion_count > 1.5;
通过 Grafana 集成 IoTDB 数据源。
实现:
交通流量热力图,实时显示各路口拥堵情况 车速趋势图,展示平均车速变化趋势 拥堵指数排行榜,快速定位高拥堵路口 实时告警看板,自动推送拥堵预警信息
Apache IoTDB 的 GROUP BY 和 HAVING 子句构成了时序数据分析的完整工具链。通过合理配置和优化,实现了查询效率提升、存储空间减少、数据完整率提高、业务洞察能力的提升。本文详细讲述了 GROUP BY 和 HAVING 子句的具体使用和案例,能够帮助开发者在实际项目中充分发挥 IoTDB 的强大功能,创造真正的业务价值。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
在线格式化和美化您的 SQL 查询(它支持各种 SQL 方言)。 在线工具,SQL 美化和格式化在线工具,online