
TDengine 在新能源领域的最佳实践
概述
新能源领域,特别是分布式光伏和储能系统,面临着海量测点、高频采集、实时监控等数据处理挑战。本文档将详细介绍如何使用 TDengine 构建高效的新能源数据管理系统,涵盖数据建模、高效写入和查询优化等核心内容。
业务场景分析
典型数据特征
- 测点规模:分布式光伏电站和储能系统的测点数量从数十万到数千万不等
- 采集频率:1 分钟级、15 分钟级的高频数据采集
- 数据类型:电流、电压、温度、功率、功率因数等多维度指标
- 层级关系:光伏电站 → 配电变压器 → 馈线 → 主网变压器的多层级结构
核心业务需求
- 海量测点数据的实时采集与存储
- 设备最新状态的快速查询
- 多维度的聚合分析(按地区、变压器、馈线等)
- 实时数据分发至各地市调度中心
- 历史数据的长期保存与分析
数据建模最佳实践
1. 超级表设计
1.1 分布式光伏电站功率表
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS energy_db
VGROUPS 16
BUFFER 256
PAGES 128
PAGESIZE 4
KEEP 3650
DURATION 1d;
-- 分布式光伏电站瞬时功率超级表
CREATE STABLE IF NOT EXISTS energy_db.dpv_power (
ts TIMESTAMP, -- 采集时间
active_power FLOAT, -- 有功功率 (kW)
reactive_power FLOAT, -- 无功功率 (kVar)
voltage_a FLOAT, -- A相电压 (V)
voltage_b FLOAT, -- B相电压 (V)
voltage_c FLOAT, -- C相电压 (V)
current_a FLOAT, -- A相电流 (A)
current_b FLOAT, -- B相电流 (A)
current_c FLOAT, -- C相电流 (A)
power_factor FLOAT, -- 功率因数
frequency FLOAT -- 频率 (Hz)
) TAGS (
station_id VARCHAR(64), -- 电站ID
station_name NCHAR(128), -- 电站名称
region VARCHAR(64), -- 所属地区
city VARCHAR(64), -- 所属城市
dtr_id VARCHAR(64), -- 所属配电变压器ID
feeder_id VARCHAR(64), -- 所属馈线ID
line_10kv_id VARCHAR(64), -- 所属10kV线端ID
transformer_110kv_id VARCHAR(64),-- 所属110kV主网变压器ID
capacity FLOAT, -- 装机容量 (kW)
install_date TIMESTAMP, -- 安装日期
longitude DOUBLE, -- 经度
latitude DOUBLE -- 纬度
);
1.2 储能系统电芯监测表
sql
-- 储能电芯实时监测超级表
CREATE STABLE IF NOT EXISTS energy_db.battery_cell (
ts TIMESTAMP, -- 采集时间
voltage FLOAT, -- 电压 (V)
current FLOAT, -- 电流 (A)
temperature FLOAT, -- 温度 (℃)
soc FLOAT, -- 荷电状态 (%)
soh FLOAT, -- 健康状态 (%)
internal_resistance FLOAT, -- 内阻 (mΩ)
charge_cycles INT -- 充放电循环次数
) TAGS (
cell_id VARCHAR(64), -- 电芯ID
pack_id VARCHAR(64), -- 电池包ID
rack_id VARCHAR(64), -- 电池簇ID
station_id VARCHAR(64), -- 储能站ID
station_name NCHAR(128), -- 储能站名称
region VARCHAR(64), -- 所属地区
manufacturer NCHAR(64), -- 制造商
model NCHAR(64), -- 型号
rated_capacity FLOAT, -- 额定容量 (Ah)
install_date TIMESTAMP -- 安装日期
);
1.3 配电变压器监测表
sql
-- 配电变压器超级表
CREATE STABLE IF NOT EXISTS energy_db.transformer (
ts TIMESTAMP, -- 采集时间
load_rate FLOAT, -- 负载率 (%)
high_voltage_a FLOAT, -- 高压侧A相电压 (kV)
high_voltage_b FLOAT, -- 高压侧B相电压 (kV)
high_voltage_c FLOAT, -- 高压侧C相电压 (kV)
low_voltage_a FLOAT, -- 低压侧A相电压 (V)
low_voltage_b FLOAT, -- 低压侧B相电压 (V)
low_voltage_c FLOAT, -- 低压侧C相电压 (V)
current_a FLOAT, -- 电流A相 (A)
current_b FLOAT, -- 电流B相 (A)
current_c FLOAT, -- 电流C相 (A)
oil_temperature FLOAT, -- 油温 (℃)
winding_temperature FLOAT -- 绕组温度 (℃)
) TAGS (
dtr_id VARCHAR(64), -- 变压器ID
dtr_name NCHAR(128), -- 变压器名称
region VARCHAR(64), -- 所属地区
feeder_id VARCHAR(64), -- 所属馈线ID
rated_capacity FLOAT, -- 额定容量 (kVA)
voltage_level VARCHAR(32), -- 电压等级
install_date TIMESTAMP -- 安装日期
);
2. 子表创建策略
2.1 自动建表
使用自动建表功能可以简化开发,提高写入效率:
sql
-- 写入时自动创建子表
INSERT INTO energy_db.dpv_power_station001
USING energy_db.dpv_power
TAGS (
'station001',
'某市工业园光伏电站',
'region01',
'city01',
'dtr001',
'feeder001',
'line10kv001',
'trans110kv001',
500.0,
'2023-01-15 00:00:00',
118.78,
32.05
)
VALUES (
now,
450.5,
120.3,
220.5,
221.0,
219.8,
682.1,
680.5,
681.8,
0.95,
50.0
);
2.2 批量预创建
对于已知的设备清单,建议预先批量创建子表:
sql
-- 批量创建光伏电站子表
CREATE TABLE IF NOT EXISTS energy_db.dpv_power_station001
USING energy_db.dpv_power
TAGS ('station001', '电站1', 'region01', 'city01', 'dtr001', 'feeder001', 'line10kv001', 'trans110kv001', 500.0, '2023-01-15 00:00:00', 118.78, 32.05);
CREATE TABLE IF NOT EXISTS energy_db.dpv_power_station002
USING energy_db.dpv_power
TAGS ('station002', '电站2', 'region01', 'city01', 'dtr002', 'feeder001', 'line10kv001', 'trans110kv001', 600.0, '2023-02-20 00:00:00', 118.79, 32.06);
-- ... 更多子表
3. 数据库参数优化
sql
-- 针对新能源场景的数据库参数配置
CREATE DATABASE energy_db
VGROUPS 16 -- 根据CPU核心数调整,建议设置为CPU核心数的1-1.5倍
BUFFER 256 -- 写缓存大小(MB),根据内存情况调整
PAGES 128 -- 每个vnode的元数据缓存页数
PAGESIZE 4 -- 元数据页大小(KB)
KEEP 3650 -- 数据保留天数,3650天=10年
DURATION 1d -- 数据文件存储时长,1天一个文件
PRECISION 'ms' -- 时间精度为毫秒
REPLICA 1 -- 副本数,生产环境建议设置为3
STRICT 'off' -- 允许超级表和子表的列数不一致
CACHEMODEL 'last_row' -- 缓存每张表的最新一行数据
CACHESIZE 16; -- 缓存大小(MB)
高效写入最佳实践
1. 批量写入
1.1 使用参数绑定批量写入(推荐)
使用 Stmt(参数绑定)接口可以显著提升写入性能:
python
import taos
from datetime import datetime
# 连接数据库
conn = taos.connect(host="localhost", user="root", password="taosdata", database="energy_db")
# 创建 Stmt 对象
stmt = conn.statement("INSERT INTO ? USING dpv_power TAGS (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
# 准备批量数据
batch_size = 1000
tags_list = []
data_list = []
for i in range(batch_size):
# 表名
table_name = f"dpv_power_station{i:06d}"
# 标签数据
tags = [
f"station{i:06d}", # station_id
f"光伏电站{i}", # station_name
f"region{i % 10}", # region
f"city{i % 5}", # city
f"dtr{i % 100}", # dtr_id
f"feeder{i % 50}", # feeder_id
f"line10kv{i % 20}", # line_10kv_id
f"trans110kv{i % 10}", # transformer_110kv_id
500.0 + i, # capacity
datetime(2023, 1, 1), # install_date
118.0 + i * 0.001, # longitude
32.0 + i * 0.001 # latitude
]
# 时序数据
data = [
datetime.now(), # ts
450.0 + i * 0.1, # active_power
120.0 + i * 0.05, # reactive_power
220.0 + i * 0.01, # voltage_a
221.0 + i * 0.01, # voltage_b
219.0 + i * 0.01, # voltage_c
680.0 + i * 0.1, # current_a
681.0 + i * 0.1, # current_b
679.0 + i * 0.1, # current_c
0.95, # power_factor
50.0 # frequency
]
stmt.set_tbname_tags(table_name, tags)
stmt.bind_param(data)
# 批量执行
stmt.execute()
stmt.close()
conn.close()
1.2 SQL 批量写入
对于中小规模数据,可以使用 SQL 批量插入:
sql
-- 单条 SQL 插入多个表的多行数据
INSERT INTO
dpv_power_station001 VALUES
('2024-01-01 00:00:00', 450.5, 120.3, 220.5, 221.0, 219.8, 682.1, 680.5, 681.8, 0.95, 50.0)
('2024-01-01 00:01:00', 451.2, 120.5, 220.6, 221.1, 219.9, 682.3, 680.7, 682.0, 0.95, 50.0)
('2024-01-01 00:02:00', 452.0, 120.8, 220.7, 221.2, 220.0, 682.5, 680.9, 682.2, 0.96, 50.0)
dpv_power_station002 VALUES
('2024-01-01 00:00:00', 550.5, 130.3, 220.5, 221.0, 219.8, 782.1, 780.5, 781.8, 0.95, 50.0)
('2024-01-01 00:01:00', 551.2, 130.5, 220.6, 221.1, 219.9, 782.3, 780.7, 782.0, 0.95, 50.0);
2. 多线程并发写入
利用多线程并发写入可以充分利用系统资源:
python
import taos
import threading
from queue import Queue
from datetime import datetime
import time
class WriterThread(threading.Thread):
def __init__(self, thread_id, data_queue):
threading.Thread.__init__(self)
self.thread_id = thread_id
self.data_queue = data_queue
self.conn = taos.connect(host="localhost", user="root", password="taosdata", database="energy_db")
def run(self):
while True:
batch_data = self.data_queue.get()
if batch_data is None: # 结束信号
break
stmt = self.conn.statement("INSERT INTO ? VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
for table_name, values in batch_data:
stmt.set_tbname(table_name)
stmt.bind_param(values)
stmt.execute()
stmt.close()
self.data_queue.task_done()
self.conn.close()
# 使用示例
def parallel_write_example():
num_threads = 8
data_queue = Queue(maxsize=100)
# 创建并启动写入线程
threads = []
for i in range(num_threads):
thread = WriterThread(i, data_queue)
thread.start()
threads.append(thread)
# 生产数据
for batch in range(1000):
batch_data = []
for i in range(100):
table_name = f"dpv_power_station{batch * 100 + i:06d}"
values = [
datetime.now(),
450.0 + i,
120.0 + i,
220.0,
221.0,
219.0,
680.0,
681.0,
679.0,
0.95,
50.0
]
batch_data.append((table_name, values))
data_queue.put(batch_data)
# 等待所有任务完成
data_queue.join()
# 发送结束信号
for _ in range(num_threads):
data_queue.put(None)
# 等待所有线程结束
for thread in threads:
thread.join()
if __name__ == "__main__":
parallel_write_example()
3. 数据接入 - taosX 使用
对于从 Kafka 等外部系统接入数据的场景,使用 taosX 可以零代码快速接入:
json
{
"name": "kafka-dpv-power",
"type": "kafka",
"config": {
"bootstrap.servers": "localhost:9092",
"group.id": "taosX-dpv-consumer",
"topics": ["dpv-power-data"],
"value.deserializer": "json"
},
"transform": {
"filter": "payload.station_id != null",
"mapping": {
"table": "dpv_power_${payload.station_id}",
"supertable": "dpv_power",
"timestamp": "${payload.timestamp}",
"columns": {
"active_power": "${payload.active_power}",
"reactive_power": "${payload.reactive_power}",
"voltage_a": "${payload.voltage_a}",
"voltage_b": "${payload.voltage_b}",
"voltage_c": "${payload.voltage_c}",
"current_a": "${payload.current_a}",
"current_b": "${payload.current_b}",
"current_c": "${payload.current_c}",
"power_factor": "${payload.power_factor}",
"frequency": "${payload.frequency}"
},
"tags": {
"station_id": "${payload.station_id}",
"station_name": "${payload.station_name}",
"region": "${payload.region}",
"city": "${payload.city}",
"dtr_id": "${payload.dtr_id}",
"feeder_id": "${payload.feeder_id}",
"line_10kv_id": "${payload.line_10kv_id}",
"transformer_110kv_id": "${payload.transformer_110kv_id}",
"capacity": "${payload.capacity}",
"install_date": "${payload.install_date}",
"longitude": "${payload.longitude}",
"latitude": "${payload.latitude}"
}
}
},
"target": {
"database": "energy_db"
}
}
高效查询最佳实践
1. 最新状态查询
1.1 查询单个设备最新状态
sql
-- 查询指定光伏电站的最新数据
SELECT LAST(*) FROM energy_db.dpv_power WHERE station_id = 'station001';
-- 或者直接查询子表
SELECT LAST(*) FROM energy_db.dpv_power_station001;
1.2 查询多个设备最新状态
sql
-- 查询某个地区所有光伏电站的最新功率
SELECT
station_id,
station_name,
LAST(ts) as last_time,
LAST(active_power) as current_power,
LAST(power_factor) as current_pf
FROM energy_db.dpv_power
WHERE region = 'region01'
GROUP BY station_id, station_name;
1.3 利用缓存加速最新值查询
配置 CACHEMODEL 'last_row' 后,最新值查询将直接从内存缓存返回,性能极高:
sql
-- 查询所有电站的最新状态(从缓存读取,毫秒级响应)
SELECT
tbname,
LAST(active_power) as power,
LAST(ts) as update_time
FROM energy_db.dpv_power
GROUP BY tbname;
2. 聚合分析查询
2.1 按配电变压器聚合光伏功率
sql
-- 查询每个配电变压器下所有光伏电站的总功率
SELECT
dtr_id,
SUM(LAST(active_power)) as total_power,
COUNT(*) as station_count
FROM energy_db.dpv_power
GROUP BY dtr_id
ORDER BY total_power DESC;
2.2 按地区、馈线等多维度聚合
sql
-- 查询各地区各馈线的光伏发电情况
SELECT
region,
feeder_id,
SUM(LAST(active_power)) as total_power,
AVG(LAST(power_factor)) as avg_pf,
COUNT(*) as station_count
FROM energy_db.dpv_power
WHERE ts > NOW - 5m
GROUP BY region, feeder_id
ORDER BY region, total_power DESC;
2.3 110kV 主网变压器下辖光伏功率汇总
sql
-- 查询特定主网变压器下的所有光伏电站实时功率
SELECT
transformer_110kv_id,
SUM(LAST(active_power)) as total_active_power,
SUM(LAST(reactive_power)) as total_reactive_power,
COUNT(*) as station_count
FROM energy_db.dpv_power
WHERE transformer_110kv_id = 'trans110kv001'
GROUP BY transformer_110kv_id;
3. 时序统计分析
3.1 时间窗口聚合
sql
-- 查询最近24小时每小时的平均发电功率
SELECT
_wstart as time_window,
AVG(active_power) as avg_power,
MAX(active_power) as max_power,
MIN(active_power) as min_power
FROM energy_db.dpv_power_station001
WHERE ts > NOW - 24h
INTERVAL(1h);
3.2 降采样查询
sql
-- 对1分钟数据进行15分钟降采样
SELECT
_wstart,
station_id,
AVG(active_power) as avg_power,
FIRST(voltage_a) as first_voltage_a,
LAST(temperature) as last_temp
FROM energy_db.dpv_power
WHERE ts BETWEEN '2024-01-01 00:00:00' AND '2024-01-01 23:59:59'
PARTITION BY station_id
INTERVAL(15m);
3.3 填充缺失数据
sql
-- 使用 FILL 处理数据缺失
SELECT
_wstart,
AVG(active_power) as avg_power
FROM energy_db.dpv_power_station001
WHERE ts > NOW - 24h
INTERVAL(5m)
FILL(PREV); -- 使用前一个值填充
-- 或使用线性插值
FILL(LINEAR);
-- 或使用固定值填充
FILL(VALUE, 0);
4. 电池健康状态监控
4.1 查询异常电芯
sql
-- 查询温度异常的电芯
SELECT
cell_id,
pack_id,
station_name,
LAST(temperature) as current_temp,
LAST(voltage) as current_voltage,
LAST(ts) as last_update
FROM energy_db.battery_cell
WHERE LAST(temperature) > 45 OR LAST(temperature) < -10
GROUP BY cell_id, pack_id, station_name;
-- 查询SOC异常的电芯
SELECT
cell_id,
pack_id,
LAST(soc) as current_soc,
LAST(soh) as current_soh
FROM energy_db.battery_cell
WHERE LAST(soc) < 10 OR LAST(soc) > 95
GROUP BY cell_id, pack_id;
4.2 电芯一致性分析
sql
-- 分析同一电池包内电芯的电压一致性
SELECT
pack_id,
MAX(LAST(voltage)) - MIN(LAST(voltage)) as voltage_diff,
STDDEV(LAST(voltage)) as voltage_stddev,
COUNT(*) as cell_count
FROM energy_db.battery_cell
GROUP BY pack_id
HAVING voltage_diff > 0.05 -- 压差超过50mV
ORDER BY voltage_diff DESC;
5. 负载分析
5.1 变压器负载率统计
sql
-- 查询负载率超过80%的变压器
SELECT
dtr_id,
dtr_name,
LAST(load_rate) as current_load_rate,
LAST(oil_temperature) as current_oil_temp
FROM energy_db.transformer
WHERE LAST(load_rate) > 80
GROUP BY dtr_id, dtr_name
ORDER BY current_load_rate DESC;
5.2 负载曲线分析
sql
-- 查询变压器的日负载曲线
SELECT
_wstart,
AVG(load_rate) as avg_load,
MAX(load_rate) as peak_load,
AVG(oil_temperature) as avg_temp
FROM energy_db.transformer
WHERE dtr_id = 'dtr001' AND ts > NOW - 1d
INTERVAL(15m);
数据分发最佳实践
1. 使用 TMQ 订阅实时数据
python
from taos.tmq import Consumer
# 创建消费者
consumer = Consumer({
"group.id": "city_dispatch_center_01",
"td.connect.host": "localhost",
"td.connect.port": "6030",
"td.connect.user": "root",
"td.connect.pass": "taosdata",
"auto.offset.reset": "latest"
})
# 订阅主题(超级表或数据库)
consumer.subscribe(["energy_db.dpv_power"])
# 消费数据
while True:
records = consumer.poll(timeout=1.0)
if records:
for record in records:
# 处理数据
print(f"Table: {record.table_name()}, Data: {record.value()}")
# 将数据写入本地TDengine
# ...
consumer.close()
2. 创建订阅主题
sql
-- 创建特定地区的数据订阅主题
CREATE TOPIC city01_dpv_power AS
SELECT * FROM energy_db.dpv_power WHERE city = 'city01';
-- 创建所有光伏数据的订阅主题
CREATE TOPIC all_dpv_power AS
SELECT * FROM energy_db.dpv_power;
性能优化建议
1. 硬件配置建议
- CPU: 16核心或更高,支持并发写入和查询
- 内存: 64GB或更高,用于缓存和查询
- 磁盘: SSD,建议 NVMe,提供高IOPS
- 网络: 万兆网卡,降低网络延迟
2. 系统参数调优
bash
# /etc/taos/taos.cfg
# 最大并发连接数
maxConnections 50000
# 查询线程数(建议设置为CPU核心数)
queryThreadNum 16
# 写入线程池大小
numOfThreadsPerCore 2.0
# WAL相关参数
walLevel 1
walFsyncPeriod 1000
# 查询缓存配置
querySmaOptimize 1
queryBufferSize 1024
# 压缩配置
compression 2
compressMsgSize 1024
# 调试和日志
logKeepDays 10
asyncLog 1
3. 查询优化技巧
3.1 使用标签过滤
标签过滤比数据列过滤快得多:
sql
-- 推荐:使用标签过滤
SELECT * FROM energy_db.dpv_power WHERE region = 'region01';
-- 不推荐:使用数据列过滤(需要扫描所有数据)
SELECT * FROM energy_db.dpv_power WHERE active_power > 400;
3.2 合理使用时间范围
始终指定时间范围,避免全表扫描:
sql
-- 推荐:指定时间范围
SELECT * FROM energy_db.dpv_power
WHERE ts > NOW - 1h AND region = 'region01';
-- 不推荐:不指定时间范围
SELECT * FROM energy_db.dpv_power WHERE region = 'region01';
3.3 使用子查询优化复杂查询
sql
-- 先筛选后聚合,性能更好
SELECT
region,
SUM(power) as total_power
FROM (
SELECT
region,
LAST(active_power) as power
FROM energy_db.dpv_power
WHERE ts > NOW - 5m
GROUP BY station_id, region
)
GROUP BY region;
运维监控最佳实践
1. 监控关键指标
sql
-- 查看数据库状态
SHOW DATABASES;
-- 查看vnode分布
SHOW VGROUPS;
-- 查看表数量
SELECT COUNT(*) FROM information_schema.ins_tables
WHERE db_name = 'energy_db';
-- 查看磁盘使用情况
SHOW energy_db.VGROUPS;
2. 数据维护
创建数据库时指定的 KEEP 参数,过期数据会自动清理,无需手动清理。
可定期执行 compact 操作(碎片整理),对乱序数据重新整理。
3. 告警规则示例
sql
-- 创建流式计算监控电站异常
CREATE STREAM dpv_alert_stream
INTO alert_table
AS
SELECT
_wstart,
station_id,
AVG(active_power) as avg_power,
MAX(active_power) as max_power
FROM energy_db.dpv_power
WHERE active_power > capacity * 1.1 -- 超过额定容量110%
INTERVAL(1m);
总结
本最佳实践文档涵盖了新能源领域使用 TDengine 的核心场景:
- 数据建模:通过超级表+子表的设计,利用标签进行多维度分类
- 高效写入:批量写入、参数绑定、多线程并发、taosX 数据接入
- 高效查询:最新值缓存、标签过滤、时间窗口聚合、流式计算
- 数据分发:TMQ 消息队列实现实时数据分发
- 性能优化:硬件配置、系统参数调优、查询优化
通过遵循这些最佳实践,可以构建高性能、高可靠的新能源数据管理系统,满足海量测点、高频采集、实时监控等业务需求。
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。