当前位置: 首页 > news >正文

TDengine 选择函数 Last() 用户手册

在这里插入图片描述

LAST() 函数用户手册

函数定义

LAST(expr)

功能说明

LAST() 函数统计表/超级表中某列的值最后写入的非 NULL 值,即返回时间戳最大的非 NULL 值。

版本要求

  • 最低版本: v3.0.0.0

返回值

  • 数据类型: 同应用的字段
  • 返回内容: 时间戳最大的非 NULL 值及其对应的时间戳

参数说明

参数类型说明取值范围
expr任意类型要统计的字段表达式或 *所有字段类型

适用数据类型

  • 所有字段类型: 支持所有数据类型,包括数值类型、字符串类型、时间戳类型等

适用范围

  • 表类型: 表和超级表
  • 查询支持: 支持聚合查询、窗口查询
  • 多结果函数: 支持多列返回

使用说明

  1. NULL 值处理: 忽略 NULL 值,只返回非 NULL 值
  2. 时间戳关联: 返回值对应时间戳最大的记录
  3. 复合主键: 对于存在复合主键的表,若最大时间戳的数据有多条,则返回复合主键最大的数据
  4. 全 NULL 处理:
    • 如果某列全部为 NULL 值,则该列返回结果也是 NULL
    • 如果所有列全部为 NULL 值,则不返回结果
  5. LAST(*): 支持查询所有列的最后一个非 NULL 值
  6. 随机性: 在用于超级表时,时间戳完全一样且同为最大的数据行可能有多个,会从中随机返回一条,不保证多次运行所挑选的数据行必然一致

基本用法示例

单列查询

-- 获取电流的最后一个非 NULL 值
SELECT LAST(current) FROM meters;-- 获取电压的最后一个非 NULL 值
SELECT LAST(voltage) FROM meters;-- 获取相位的最后一个非 NULL 值
SELECT LAST(phase) FROM meters;

多列查询

-- 获取多个字段的最后一个非 NULL 值
SELECT LAST(current), LAST(voltage), LAST(phase) FROM meters;-- 使用 LAST(*) 查询所有列的最后一个非 NULL 值
SELECT LAST(*) FROM meters;

NULL 值处理

-- LAST 函数自动忽略 NULL 值
SELECT LAST(current) FROM meters;
-- 只返回非 NULL 的最后值

智能电表场景应用示例

基于智能电表数据库结构:

-- 数据库和表结构
USE test;
-- meters 超级表包含 ts, current, voltage, phase 字段和 location, groupid 标签

场景1:设备最新状态监控

-- 查找每个电表的最新运行数据
SELECT tbname,LAST(current) as latest_current,LAST(voltage) as latest_voltage,LAST(phase) as latest_phase
FROM meters 
GROUP BY tbname;

场景2:按区域查找最新数据

-- 查找每个区域最新的用电记录
SELECT location,LAST(current) as latest_current,LAST(voltage) as latest_voltage,LAST(phase) as latest_phase
FROM meters 
GROUP BY location;

场景3:设备组最新状态分析

-- 分析不同设备组的最新运行情况
SELECT groupid,location,LAST(*) 
FROM meters 
GROUP BY groupid, location
ORDER BY groupid;

场景4:数据完整性检查

-- 检查各电表最新数据的完整性
SELECT tbname,CASE WHEN LAST(current) IS NULL THEN '电流数据缺失'WHEN LAST(voltage) IS NULL THEN '电压数据缺失'WHEN LAST(phase) IS NULL THEN '相位数据缺失'ELSE '数据完整'END as data_status,LAST(current) as latest_current,LAST(voltage) as latest_voltage,LAST(phase) as latest_phase
FROM meters 
GROUP BY tbname;

场景5:实时监控面板

-- 获取各电表的实时监控数据
SELECT tbname,location,groupid,LAST(current) as realtime_current,LAST(voltage) as realtime_voltage,LAST(phase) as realtime_phase
FROM meters 
GROUP BY tbname, location, groupid
HAVING LAST(current) IS NOT NULL;-- 按区域统计设备状态
SELECT location,COUNT(*) as meter_count,MAX(LAST(current)) as max_current,MIN(LAST(current)) as min_current,MAX(LAST(voltage)) as max_voltage,MIN(LAST(voltage)) as min_voltage
FROM meters 
GROUP BY location;

场景6:异常设备识别

-- 识别最近异常的设备
SELECT tbname,location,LAST(current) as latest_current,LAST(voltage) as latest_voltage,CASE WHEN LAST(current) > 25.0 THEN '电流过载'WHEN LAST(voltage) < 200 OR LAST(voltage) > 240 THEN '电压异常'WHEN LAST(phase) < 0 OR LAST(phase) > 360 THEN '相位异常'ELSE '正常'END as device_status
FROM meters 
GROUP BY tbname, location
ORDER BY latest_current DESC;

场景7:设备运行时长统计

-- 计算设备从首次记录到最后记录的运行时长
SELECT tbname,location,FIRST(ts) as start_time,LAST(ts) as end_time,LAST(current) as final_current
FROM meters 
GROUP BY tbname, location;

场景8:负载变化趋势分析

-- 分析电表负载从初始到最终的变化
SELECT location,FIRST(current) as initial_current,LAST(current) as final_current,LAST(current) - FIRST(current) as current_change,CASE WHEN LAST(current) > FIRST(current) THEN '负载增加'WHEN LAST(current) < FIRST(current) THEN '负载减少'ELSE '负载稳定'END as load_trend
FROM meters 
GROUP BY location
HAVING FIRST(current) IS NOT NULL AND LAST(current) IS NOT NULL;

场景9:电能质量最新状态评估(分步查询)

-- 第一步:获取每个电表的最新数据
SELECT tbname,groupid,location,LAST(current) as latest_current,LAST(voltage) as latest_voltage,LAST(phase) as latest_phase
FROM meters 
GROUP BY tbname, groupid, location;

场景10:设备维护提醒

-- 根据最后记录时间和数据值进行维护提醒
SELECT tbname,location,LAST(ts) as last_record_time,LAST(current) as last_current_reading,CASE WHEN LAST(ts) < NOW() - 1d THEN '设备可能离线,需要检查'WHEN LAST(current) > 20.0 THEN '电流过高,需要维护'WHEN LAST(voltage) < 200 THEN '电压异常,需要检查'ELSE '设备运行正常'END as maintenance_status
FROM meters 
GROUP BY tbname, location
ORDER BY last_record_time ASC;

LAST(*) 的特殊用法

查询所有列的最后值

-- 查询超级表所有列的最后非 NULL 值
SELECT LAST(*) FROM meters;-- 按电表分组查询每个电表的最后记录
SELECT LAST(*) FROM meters GROUP BY tbname;

标签列返回控制

在 TDengine 中,LAST(*) 的行为受 multiResultFunctionStarReturnTags 参数控制:

  • 设置为 0(默认): 只返回超级表的普通列
  • 设置为 1: 返回超级表的普通列和标签列
-- 设置参数以包含标签列
SET multiResultFunctionStarReturnTags=1;
SELECT LAST(*) FROM meters;-- 恢复默认设置
SET multiResultFunctionStarReturnTags=0;

LAST 函数缓存优化

缓存机制说明

TDengine 通过数据库的 CACHEMODEL 参数来优化 LAST 函数的查询性能。当启用相应的缓存模式后,系统会在内存中缓存子表的最近数据,从而大幅提升 LAST 相关查询的响应速度。

CACHEMODEL 参数详解

CACHEMODEL 表示是否在内存中缓存子表的最近数据,有以下四种模式:

模式说明适用场景
none不缓存(默认值)内存资源紧张或不常用 LAST 查询
last_row缓存子表最近一行数据频繁使用 LAST_ROW 函数的场景
last_value缓存子表每一列的最近非 NULL 值频繁使用 LAST 函数的场景
both同时开启 last_row 和 last_value 缓存同时需要 LAST 和 LAST_ROW 高性能的场景

重要说明: last_value 模式将显著改善无特殊影响(WHERE、ORDER BY、GROUP BY、INTERVAL)下的 LAST 函数的性能表现。

启用 LAST 函数缓存

创建数据库时启用缓存
-- 创建数据库时启用 LAST 函数缓存
CREATE DATABASE test_db CACHEMODEL 'last_value';-- 创建数据库时同时启用 LAST 和 LAST_ROW 缓存
CREATE DATABASE test_db CACHEMODEL 'both';-- 完整的创建示例,包含缓存配置
CREATE DATABASE smart_meter CACHEMODEL 'last_value' CACHESIZE 16 BUFFER 256 PRECISION 'ms';
修改现有数据库启用缓存
-- 为现有数据库启用 LAST 函数缓存
ALTER DATABASE test CACHEMODEL 'last_value';-- 为现有数据库同时启用 LAST 和 LAST_ROW 缓存
ALTER DATABASE test CACHEMODEL 'both';-- 禁用缓存
ALTER DATABASE test CACHEMODEL 'none';
配置缓存大小
-- 设置每个 vnode 用于缓存的内存大小(MB)
ALTER DATABASE test CACHESIZE 32;  -- 设置为 32MB-- 同时修改缓存模式和大小
ALTER DATABASE test CACHEMODEL 'both' CACHESIZE 64;
查看缓存配置状态
-- 查看数据库的缓存配置
SELECT NAME, CACHE_MODEL, CACHE_SIZE 
FROM INFORMATION_SCHEMA.INS_DATABASES 
WHERE NAME='test';-- 查看详细的数据库配置
SHOW CREATE DATABASE test \G;-- 查看所有数据库的缓存配置
SELECT NAME, CACHE_MODEL, CACHE_SIZE 
FROM INFORMATION_SCHEMA.INS_DATABASES;

缓存使用效果示例

启用缓存后的高性能查询
-- 启用 last_value 缓存后的高效查询
-- 获取所有电表的最新非 NULL 状态(毫秒级响应)
SELECT tbname, LAST(*) FROM meters GROUP BY tbname;-- 设备在线状态检查(毫秒级响应)
SELECT tbname,location,LAST(ts) as last_seen,CASE WHEN LAST(ts) > NOW() - 5m THEN '在线'ELSE '离线'END as status
FROM meters 
GROUP BY tbname, location;
缓存监控与诊断
-- 查看 vgroup 的缓存使用情况
SHOW test.vgroups;-- 检查缓存负载
SELECT * FROM INFORMATION_SCHEMA.INS_DATABASES WHERE NAME='test';

缓存优化最佳实践

1. 缓存模式选择建议
-- 场景1:主要使用 LAST 函数的监控系统
CREATE DATABASE monitoring_db CACHEMODEL 'last_value' CACHESIZE 32;-- 场景2:同时需要 LAST 和 LAST_ROW 的实时系统
CREATE DATABASE realtime_db CACHEMODEL 'both' CACHESIZE 64;-- 场景3:内存敏感的环境
CREATE DATABASE minimal_db CACHEMODEL 'none';
2. 缓存大小调优

根据文档说明,可以通过以下方式判断和调整缓存大小:

-- 1. 查看当前 cachesize(单位:MB)
SELECT NAME, CACHE_SIZE FROM INFORMATION_SCHEMA.INS_DATABASES WHERE NAME='test';-- 2. 查看 cacheload(单位:Byte)
SHOW test.vgroups;-- 3. 根据负载情况调整
-- 如果 cacheload 非常接近 cachesize,则 cachesize 可能过小
-- 如果 cacheload 明显小于 cachesize 则 cachesize 是够用的-- 小规模部署(< 1000 设备)
ALTER DATABASE test CACHESIZE 8;-- 中等规模部署(1000-10000 设备)
ALTER DATABASE test CACHESIZE 32;-- 大规模部署(> 10000 设备)
ALTER DATABASE test CACHESIZE 128;
3. 监控缓存效果
-- 创建缓存性能监控查询
SELECT NAME as db_name,CACHE_MODEL,CACHE_SIZE,BUFFER
FROM INFORMATION_SCHEMA.INS_DATABASES 
WHERE NAME = 'test';-- 查看 vgroup 缓存负载
SHOW test.vgroups;

缓存注意事项与限制

  1. 内存消耗: 启用缓存会增加内存使用,CACHESIZE 范围为 [1, 65536] MB
  2. 数据一致性: 缓存数据与磁盘数据保持强一致性,无需担心数据不一致
  3. 适用场景: 特别适合频繁查询最新数据的实时监控场景
  4. 模式切换警告: CACHEMODEL 值来回切换有可能导致 last/last_row 的查询结果不准确,建议保持稳定配置(推荐保持打开)
  5. 缓存预热: 新启用缓存后,第一次查询可能稍慢,后续查询会显著加速
  6. 查询限制: last_value 缓存主要优化无特殊影响(WHERE、ORDER BY、GROUP BY、INTERVAL)下的 LAST 函数查询

与其他函数的对比

LAST vs FIRST

-- 对比首个值和最后值
SELECT location,FIRST(current) as first_current,LAST(current) as last_current,LAST(current) - FIRST(current) as current_change,FIRST(ts) as first_time,LAST(ts) as last_time
FROM meters 
GROUP BY location;

LAST vs MAX

-- LAST 返回时间最晚的值,MAX 返回数值最大的值
SELECT location,LAST(current) as latest_current,    -- 时间最晚的电流值MAX(current) as maximum_current     -- 数值最大的电流值
FROM meters 
GROUP BY location;

LAST vs LAST_ROW

-- LAST 和 LAST_ROW 的区别
SELECT location,LAST(current) as last_non_null_current,     -- 最后的非NULL电流值LAST_ROW(current) as last_row_current       -- 最后一行的电流值(可能为NULL)
FROM meters 
GROUP BY location;

TDengine 函数嵌套限制说明

不支持的嵌套方式

-- 以下写法都会报错:
-- AVG(LAST(current))          -- 聚合函数嵌套选择函数
-- SUM(FIRST(voltage))         -- 聚合函数嵌套选择函数  
-- COUNT(TOP(current, 1))      -- 聚合函数嵌套选择函数
-- MAX(LAST(phase))            -- 聚合函数嵌套选择函数

推荐的替代方案

  1. 分步查询:先用 LAST 获取数据,再在外层或应用层计算聚合
  2. 使用单层聚合:直接使用 MAX、MIN、COUNT 等函数
  3. 子查询:如果支持,使用子查询分离不同层次的聚合

正确的查询模式

-- 模式1:单层查询
SELECT location,LAST(current) as latest_current,MAX(current) as max_current,MIN(current) as min_current,COUNT(*) as record_count
FROM meters 
GROUP BY location;-- 模式2:分层查询(推荐)
-- 第一层:获取每个设备的最新数据
SELECT tbname,location, LAST(current) as latest_current
FROM meters 
GROUP BY tbname, location;
-- 第二层:在应用层计算区域统计

性能优化建议

1. 缓存优化

-- 为高频 LAST 查询启用缓存
ALTER DATABASE test CACHEMODEL 'last_value' CACHESIZE 64;

2. 查询优化

-- 使用合适的时间范围过滤
SELECT LAST(current) FROM meters 
WHERE ts >= NOW() - 1d
GROUP BY location;-- 避免不必要的复杂条件
SELECT LAST(*) FROM meters GROUP BY tbname;

3. 索引优化

-- 确保时间戳字段有适当的索引(TDengine 自动处理)
-- 合理设计标签字段以优化分组查询

常见问题与解决方案

1. 查询性能问题

问题: LAST 查询响应慢
解决方案:

-- 启用 last_value 缓存
ALTER DATABASE your_db CACHEMODEL 'last_value';
-- 调整缓存大小
ALTER DATABASE your_db CACHESIZE 32;

2. 内存使用过高

问题: 缓存占用内存过多
解决方案:

-- 先检查当前缓存使用情况
SHOW your_db.vgroups;-- 减少缓存大小
ALTER DATABASE your_db CACHESIZE 16;
-- 或关闭缓存
ALTER DATABASE your_db CACHEMODEL 'none';

3. 结果不一致

问题: 频繁切换 CACHEMODEL 导致结果不准确
解决方案: 保持稳定的缓存配置,避免频繁切换

4. 聚合函数嵌套错误

问题: AVG(LAST(current)) 报错
解决方案: 使用分步查询或单层聚合函数

注意事项

  1. 时间戳依赖: LAST 函数依赖于时间戳排序,确保时间戳字段的准确性
  2. NULL值忽略: 函数自动忽略 NULL 值,只返回非 NULL 值
  3. 复合主键: 对于有复合主键的表,相同时间戳的记录会按主键排序
  4. 随机性: 超级表查询时,相同最大时间戳的多条记录会随机选择一条
  5. 缓存配置: 启用缓存会增加内存消耗,需要根据系统资源合理配置
  6. 结果完整性:
    • 单列全为 NULL 时,该列结果为 NULL
    • 所有列全为 NULL 时,不返回任何结果
  7. 配置稳定性: 建议保持 CACHEMODEL 配置稳定,避免频繁更改
  8. 函数嵌套限制: 不支持在聚合函数内嵌套 LAST 函数

相关函数

  • FIRST(): 返回最先(时间戳最小)的非 NULL 值
  • LAST_ROW(): 返回最后一条记录(可能包含 NULL 值)
  • MAX(): 返回数值最大的值
  • MIN(): 返回数值最小的值
  • TOP(): 返回最大的 k 个值
  • BOTTOM(): 返回最小的 k 个值

关于 TDengine

TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。


文章转载自:

http://NHUzTfPJ.zxhhy.cn
http://j6oorIIJ.zxhhy.cn
http://nwuPPdqS.zxhhy.cn
http://FqlgRUlE.zxhhy.cn
http://3W7vyT1G.zxhhy.cn
http://mJoJLTAS.zxhhy.cn
http://t6fE0tKv.zxhhy.cn
http://czjN1Ktk.zxhhy.cn
http://ag4VOnu2.zxhhy.cn
http://2AlM5s6i.zxhhy.cn
http://agedCbBy.zxhhy.cn
http://XVQCL1zs.zxhhy.cn
http://JSQhjyMa.zxhhy.cn
http://Ycyxvqzi.zxhhy.cn
http://6O0hw9qi.zxhhy.cn
http://n84bu5Mc.zxhhy.cn
http://2kSQGKXY.zxhhy.cn
http://iQBVxdwB.zxhhy.cn
http://syhKR7gd.zxhhy.cn
http://3tPoevbY.zxhhy.cn
http://mBMx3myk.zxhhy.cn
http://gDKan8I7.zxhhy.cn
http://Sv1PEEIQ.zxhhy.cn
http://gdMCIyPn.zxhhy.cn
http://Ke9CZeqc.zxhhy.cn
http://h0eQlVIe.zxhhy.cn
http://x9vfLiGC.zxhhy.cn
http://QNNZTkTy.zxhhy.cn
http://3ZLDacB9.zxhhy.cn
http://noibJlxM.zxhhy.cn
http://www.dtcms.com/a/374278.html

相关文章:

  • MySQL的数据模型
  • vulnhub:Kioptrix level 2
  • C++ Int128 —— 128位有符号整数类实现剖析
  • 前端部署,又有新花样?
  • Neural Jacobian Field学习笔记 - omegaconf
  • C++(day8)
  • 设计模式:模板方法模式
  • 英发睿能闯关上市:业绩波动明显,毅达创投退出,临场“移民”
  • 华清远见25072班网络编程day1
  • 深入理解 AbstractQueuedSynchronizer (AQS):Java 并发的排队管家
  • 32位CPU架构是如何完成两数(32位)相加的指令的?
  • 深度学习中的损失函数都有哪些,大模型时代主要用的损失函数有哪些,中间有什么区别?
  • java:io流相关类的继承关系梳理
  • PAT 1004 Counting Leaves
  • Linux操作系统shell脚本语言-第六章
  • 基于Springboot + vue3实现的小区物业管理系统
  • 自动化测试DroidRun
  • 把一段 JSON 字符串还原成一个实体对象
  • YOLO系列论文梳理(AI版)
  • ARM内核知识概念
  • 图论相关经典题目练习及详解
  • 深圳比斯特|多维度分选:圆柱电池品质管控的自动化解决方案
  • MySQL 日志全解析:Binlog/Redo/Undo 等 5 类关键日志的配置、作用与最佳实践
  • 龙虎榜——20250908
  • 自噬机制解析(二):一文厘清 LC3/Atg8 概念及实验应用要点
  • java类加载过程
  • 20250908-02:运行第一个 LLM 调用程序
  • 基于A2A和ADK的内容规划代理
  • 电流源电路
  • 随机获取数组内任意元素