LAST() 函數用戶手冊
函數定義
LAST(expr)
功能說明
LAST()
函數統計表/超級表中某列的值最后寫入的非 NULL 值,即返回時間戳最大的非 NULL 值。
版本要求
- 最低版本: v3.0.0.0
返回值
- 數據類型: 同應用的字段
- 返回內容: 時間戳最大的非 NULL 值及其對應的時間戳
參數說明
參數 | 類型 | 說明 | 取值范圍 |
---|---|---|---|
expr | 任意類型 | 要統計的字段表達式或 * | 所有字段類型 |
適用數據類型
- 所有字段類型: 支持所有數據類型,包括數值類型、字符串類型、時間戳類型等
適用范圍
- 表類型: 表和超級表
- 查詢支持: 支持聚合查詢、窗口查詢
- 多結果函數: 支持多列返回
使用說明
- NULL 值處理: 忽略 NULL 值,只返回非 NULL 值
- 時間戳關聯: 返回值對應時間戳最大的記錄
- 復合主鍵: 對于存在復合主鍵的表,若最大時間戳的數據有多條,則返回復合主鍵最大的數據
- 全 NULL 處理:
- 如果某列全部為 NULL 值,則該列返回結果也是 NULL
- 如果所有列全部為 NULL 值,則不返回結果
- LAST(*): 支持查詢所有列的最后一個非 NULL 值
- 隨機性: 在用于超級表時,時間戳完全一樣且同為最大的數據行可能有多個,會從中隨機返回一條,不保證多次運行所挑選的數據行必然一致
基本用法示例
單列查詢
-- 獲取電流的最后一個非 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;
緩存注意事項與限制
- 內存消耗: 啟用緩存會增加內存使用,CACHESIZE 范圍為 [1, 65536] MB
- 數據一致性: 緩存數據與磁盤數據保持強一致性,無需擔心數據不一致
- 適用場景: 特別適合頻繁查詢最新數據的實時監控場景
- 模式切換警告: CACHEMODEL 值來回切換有可能導致 last/last_row 的查詢結果不準確,建議保持穩定配置(推薦保持打開)
- 緩存預熱: 新啟用緩存后,第一次查詢可能稍慢,后續查詢會顯著加速
- 查詢限制: 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)) -- 聚合函數嵌套選擇函數
推薦的替代方案
- 分步查詢:先用 LAST 獲取數據,再在外層或應用層計算聚合
- 使用單層聚合:直接使用 MAX、MIN、COUNT 等函數
- 子查詢:如果支持,使用子查詢分離不同層次的聚合
正確的查詢模式
-- 模式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))
報錯
解決方案: 使用分步查詢或單層聚合函數
注意事項
- 時間戳依賴: LAST 函數依賴于時間戳排序,確保時間戳字段的準確性
- NULL值忽略: 函數自動忽略 NULL 值,只返回非 NULL 值
- 復合主鍵: 對于有復合主鍵的表,相同時間戳的記錄會按主鍵排序
- 隨機性: 超級表查詢時,相同最大時間戳的多條記錄會隨機選擇一條
- 緩存配置: 啟用緩存會增加內存消耗,需要根據系統資源合理配置
- 結果完整性:
- 單列全為 NULL 時,該列結果為 NULL
- 所有列全為 NULL 時,不返回任何結果
- 配置穩定性: 建議保持 CACHEMODEL 配置穩定,避免頻繁更改
- 函數嵌套限制: 不支持在聚合函數內嵌套 LAST 函數
相關函數
FIRST()
: 返回最先(時間戳最小)的非 NULL 值LAST_ROW()
: 返回最后一條記錄(可能包含 NULL 值)MAX()
: 返回數值最大的值MIN()
: 返回數值最小的值TOP()
: 返回最大的 k 個值BOTTOM()
: 返回最小的 k 個值
關于 TDengine
TDengine 專為物聯網IoT平臺、工業大數據平臺設計。其中,TDengine TSDB 是一款高性能、分布式的時序數據庫(Time Series Database),同時它還帶有內建的緩存、流式計算、數據訂閱等系統功能;TDengine IDMP 是一款AI原生工業數據管理平臺,它通過樹狀層次結構建立數據目錄,對數據進行標準化、情景化,并通過 AI 提供實時分析、可視化、事件管理與報警等功能。