工业传感器数据天然适合用 SQL 聚合数一数上报了多少条算一算平均温度找出最高值和最低值。但真落到时序场景里问题会变复杂设备可能漏报字段可能是NULL同一时间段内不同设备的采样间隔也未必一致。KWDB SampleDB 的aggregate示例把这些边界放进了一套可运行的数据里。它用一张传感器时序表把基础统计聚合和时序专属聚合放在同一个业务背景下观察。样例数据如下01 示例数据如何组织直接从aggregate目录开始generate_data.sh生成 CSVcreate_load.sql建库建表并导入数据query.sql执行聚合查询。表结构的核心是sensors.sensor_data。ts是采集时间temperature、temperature2、temperature3表示不同整数精度的温度值stress、stress2表示不同浮点精度的压力值ptagID是传感器编号并作为主标签区分设备。这组数据只有 29 行但设计得有针对性• ptagID1/2/3是比较规整的递增数据适合观察基础聚合结果。• ptagID5包含负数能验证最小值、最大值、平均值是否按真实数值计算。• ptagID6/7/8包含大量空值并在 16:00 到 20:00 附近制造了不完全一致的采样时间适合观察NULL处理、末值和时间加权平均。写时序 SQL 时容易漏掉这一层聚合函数处理的不只是列值还包含哪些行参与计算、“时间顺序如何解释”、设备标签是否要分组等业务约束。02 基础统计聚合先回答数据概况基础聚合函数回答常见问题数据有多少、均值是多少、总量是多少、边界在哪里、波动大不大。COUNT先确认数据是否完整COUNT(*)统计行数适合做数据上报完整性检查。示例里用它查看ptagID3的记录数SELECT COUNT(*)这类查询的价值来自前置校验。设备本来应该每分钟上报一次如果COUNT(*)明显偏少后面的平均值、最大值再漂亮也可能没有解释意义。需要注意的是COUNT(*)和COUNT(column)不是一回事。前者统计行后者统计指定列的非空值。SampleDB 里后半段数据刻意放入了很多空字段所以在真实排障时二者往往应该一起看。AVG、SUM聚合前先想清楚维度平均温度通常不能只算全局值因为不同设备的工况可能完全不同。示例里按传感器编号分组SELECT ptagid, AVG(temperature)这条 SQL 的业务含义是每台设备自己的平均温度。如果去掉GROUP BY ptagid得到的就是所有设备混在一起的平均值适合看总体水平却不适合定位单台设备异常。SUM(stress)则更像累计量分析SELECT SUM(stress)这里先通过WHERE限定时间范围再聚合压力值。这个顺序决定了哪些采样点进入统计口径。MIN、MAX边界值更接近告警语义MIN和MAX常用于异常低点、超温、过载这类场景。SampleDB 的写法仍然按ptagid分组SELECT ptagid, MIN(temperature), MAX(temperature)按设备分组更贴近排障。全局最大温度只能告诉你有设备到过高位按设备分组后才知道是哪台设备以及它自己的上下界是否异常。ptagID5的负数数据值得保留。它提醒我们传感器输出数值不一定都是正数不要在应用层用负数就是脏数据的先验去覆盖数据库里的真实观测。STDDEV均值稳定不代表运行稳定平均值只能说明中心位置标准差才更接近波动程度。SELECT ptagid, AVG(temperature), STDDEV(temperature)如果两台设备平均温度接近但其中一台标准差明显更大排查方向就不应该只盯着均值而要看它是否存在周期性抖动、采样异常或工况切换。SampleDB 把AVG和STDDEV放在同一条查询里提醒你同时看中心值和离散程度。03 时序专属聚合把时间顺序纳入计算普通聚合把一批行压缩成一个结果时序聚合则进一步追问这些行在时间轴上是怎么排列的FIRST、LAST不是最小值和最大值FIRST和LAST关注的是时间顺序不是数值大小。SELECT first(temperature) AS first_temp这两个函数适合回答最早采集到的值是什么以及最新有效值是什么。在监控面板里LAST往往比MAX更接近实时状态在设备启动分析里FIRST又比MIN更接近初始工况。真实业务中通常还会把它们和设备标签一起使用例如按ptagid分组查看每台设备的最新值。否则全表级别的LAST只能代表整个数据集的最后状态不一定能代表每一台设备。time_bucket把高频数据压成固定窗口时序数据一旦进入高频采集直接看原始点会很吵。time_bucket的作用是把时间轴切成固定窗口再在窗口内做聚合。SampleDB 用 2 小时窗口取末值SELECT time_bucket(ts, 2h) AS bucket, last(temperature)time_bucket完成降采样保留趋势减少点数。它适合画折线图、日报看板或长周期巡检报表。有一个规则不能省time_bucket()生成的是分组维度必须配合GROUP BY使用。否则数据库不知道每个时间桶应该如何合并多行数据。TWA非均匀采样下普通平均值可能误导AVG默认每条记录权重相同。但时序数据里采样点之间的时间间隔可能不同。一个温度值持续 5 分钟另一个温度值持续 50 分钟如果简单平均它们会被当成同等重要。TWA解决的是这个问题把时间间隔纳入平均值计算更适合非均匀采样数据。SELECT twa(ts, temperature)第二条查询也说明KWDB 支持先对字段做算术表达式再参与聚合。工业场景经常需要先换算单位、套用校准系数或者把原始采集值转换成业务指标后再统计。04 实操技巧SampleDB 查询逻辑简洁这里整理几条可复用的实践要点1. 定好统计口径全表聚合看总量ptagid 分组对比设备差异time_bucket 分桶分析时序趋势口径模糊会导致结果误判。2. 明确NULL业务意义聚合函数自动忽略空值但 NULL 代表未上报、字段无效、采集/导入失败数据库不会自动解读空值背后的业务场景。3. 分清两类边界函数MIN/MAX 取数值极值FIRST/LAST 按时间取首尾监控、告警、设备排查、复盘等场景对边界数据需求不同。4. 非均匀采样慎用 AVG采样间隔不均会扭曲均值结论推荐使用 TWA 时间加权平均这是时序库聚合区别于普通关系库的关键能力。05 小结KWDB SampleDB 的aggregate示例覆盖了两类聚合能力COUNT、AVG、SUM、MIN、MAX、STDDEV负责基础统计FIRST、LAST、time_bucket、TWA则把时间顺序、窗口和采样间隔纳入分析。这组示例的价值来自它把聚合函数放进了传感器数据的真实约束里多设备、空值、负数、非均匀采样、时间窗口。理解这些约束再去写聚合 SQL结果才更接近业务事实。SampleDB 项目后续还会持续更新更多信息可查阅KWDB SampleDB 官网https://kwdb.tech/sampledb 及开源仓库https://gitee.com/kwdb/sampledb。欢迎在社区微信群、Gitee/GitHub Issue 提出反馈与建议期待与您共同完善项目。