4、数据存储方案:时序数据库选型(InfluxDB/TDengine)、关系型数据库设计、数据压缩策略
说到数据存储,我得先跟你交个底——电表数据这玩意儿,跟普通业务数据完全是两码事。
你想想看,一个中型园区,几百个电表,每15秒采集一次。一天下来就是几百万条记录。一年呢?几个亿。这还只是电表,还没算上断路器状态、变压器温度、光伏逆变器数据……
所以,选存储方案,说白了就是选「活路」。选错了,后面查询慢、存储贵、维护难,哭都来不及。
核心结论先放这:
- 时序数据(电表读数、功率、电压)→ 时序数据库
- 配置数据(电表参数、用户信息、设备台账)→ 关系型数据库
- 历史归档数据 → 压缩策略 + 冷热分离
4.1 时序数据库选型:InfluxDB vs TDengine
时序数据库,就是专门为「带时间戳的数值」设计的。普通数据库存这种数据,效率低得吓人。
我这些年用过InfluxDB,也深度用过TDengine。各有千秋,我跟你聊聊真实感受。
4.1.1 InfluxDB:老牌劲旅,生态成熟
InfluxDB 1.x 版本我用了三年多。说实话,上手是真的快。
- 安装简单:一条命令搞定,不用折腾集群
- 查询语法友好:类SQL的InfluxQL,工程师基本零门槛
- 数据保留策略(RP):自动过期删除,省心
- 连续查询(CQ):自动降采样,把原始数据聚合成分钟级、小时级
但坑也有。我记得有一次项目,电表数量从500个扩展到2000个,InfluxDB的写入性能直接崩了。后来查了半天,发现是磁盘IO扛不住了。InfluxDB的单机版,写入瓶颈很明显。
避坑指南:我曾经在某个光伏监控项目里,用InfluxDB存逆变器数据。一开始好好的,三个月后查询越来越慢。后来发现是tag(标签)设计得太细了——每个逆变器ID都当tag,导致series基数爆炸。记住:tag的基数不要超过100万,否则性能断崖式下跌。
4.1.2 TDengine:国产新秀,性能怪兽
TDengine是涛思数据的产品。我第一次接触是2020年,当时抱着试试看的心态。
结果一用就回不去了。为什么?
- 写入速度极快:单机每秒能写几百万条,InfluxDB的5-10倍
- 压缩比惊人:我实测过,原始数据压缩后只有原来的1/7到1/10
- 超级表(Super Table):这个设计太聪明了。一张超级表定义结构,每个电表自动创建子表,查询时自动聚合
- SQL兼容:直接写标准SQL,不用学新语法
不过,TDengine也有短板。它的生态不如InfluxDB丰富,可视化工具少一些。而且,如果你要存非时序数据(比如字符串日志),它就不太合适了。
| 对比维度 | InfluxDB | TDengine |
|---|---|---|
| 写入性能 | 中等(单机约10万点/秒) | 极高(单机百万级) |
| 压缩比 | 约3:1 | 约7:1 ~ 10:1 |
| 查询语法 | InfluxQL / Flux | 标准SQL |
| 集群能力 | 企业版才支持 | 开源版支持 |
| 学习成本 | 低 | 极低(会SQL就行) |
| 适用场景 | 中小规模、快速原型 | 大规模、高并发、工业级 |
我的建议:如果你是新项目,电表数量超过1000个,直接上TDengine。如果只是几十个电表做实验,InfluxDB更省事。
4.2 关系型数据库设计:别把所有鸡蛋放一个篮子里
时序数据库管「数据」,关系型数据库管「元数据」。
什么是元数据?电表的型号、安装位置、所属用户、倍率参数、通信协议……这些信息变化频率低,但需要关联查询、事务支持。这就是关系型数据库的活儿。
我个人习惯用PostgreSQL。MySQL也行,但PostgreSQL对JSON、数组、地理信息的支持更好,做能源管理系统很合适。
4.2.1 核心表设计
我直接给你看一个实际项目的表结构,你照着抄都行。
-- 电表台账表
CREATE TABLE meter_asset (
meter_id VARCHAR(32) PRIMARY KEY, -- 电表ID,如 'MTR-2024-001'
meter_name VARCHAR(64) NOT NULL, -- 电表名称
meter_type VARCHAR(16), -- 类型:三相/单相
install_location VARCHAR(128), -- 安装位置
ct_ratio DECIMAL(10,2) DEFAULT 1, -- 电流互感器变比
pt_ratio DECIMAL(10,2) DEFAULT 1, -- 电压互感器变比
comm_protocol VARCHAR(16), -- 通信协议:Modbus/DLT645
comm_address VARCHAR(32), -- 通信地址
status SMALLINT DEFAULT 1, -- 状态:1正常 0停用
created_at TIMESTAMP DEFAULT NOW()
);
-- 用户-电表关联表
CREATE TABLE user_meter_rel (
user_id VARCHAR(32) NOT NULL,
meter_id VARCHAR(32) NOT NULL,
role VARCHAR(16) DEFAULT 'owner', -- owner/viewer
PRIMARY KEY (user_id, meter_id)
);
-- 采集任务配置表
CREATE TABLE collect_task (
task_id SERIAL PRIMARY KEY,
meter_id VARCHAR(32) NOT NULL,
interval_sec INT DEFAULT 15, -- 采集间隔,单位秒
data_items JSONB, -- 采集项,如 ["voltage","current","power"]
is_active BOOLEAN DEFAULT TRUE
);
嗯,这里要注意:千万别把时序数据往关系型数据库里塞。我见过有人把电表读数直接存MySQL,一个月后表就有几千万行,查询一条数据要好几秒。这不是找罪受吗?
4.3 数据压缩策略:省钱省空间
数据压缩,说白了就是「用时间换空间」。但压缩策略选得好,空间省了,查询速度还不慢。
4.3.1 时序数据库自带的压缩
无论是InfluxDB还是TDengine,底层都用了列式存储+压缩算法。
- InfluxDB:使用Facebook的ZSTD算法,对浮点数压缩效果不错
- TDengine:自研的压缩算法,针对工业时序数据做了优化。我实测过,同样的电表数据,TDengine的存储空间只有InfluxDB的1/3
4.3.2 降采样(Downsampling)
这是最实用的压缩策略。没有之一。
原始数据是15秒一条,但做日报、月报时,你根本不需要这么高的精度。
-- TDengine 示例:创建降采样视图
CREATE TABLE meter_data_hourly AS
SELECT
_wstart AS time_bucket,
meter_id,
AVG(power) AS avg_power,
MAX(power) AS max_power,
MIN(power) AS min_power,
SUM(energy) AS total_energy
FROM meter_data
INTERVAL(1h);
你看,原始数据如果一天有5760条(15秒间隔),降采样到小时级就只剩24条。存储量直接降到1/240。
我的经验:保留三份数据——原始数据保留7天(用于故障分析),分钟级数据保留3个月(用于日常监控),小时级数据保留3年(用于报表和审计)。这样既保证了查询速度,又控制了存储成本。
4.3.3 死区压缩(Deadband Compression)
这个技巧可能很多人不知道。电表数据有个特点:大部分时间变化很小。比如电压,稳定在220V左右,波动不超过±2%。
死区压缩的思路是:如果新数据跟上一个数据相比,变化不超过阈值,就不存。
// 伪代码示例
function shouldStore(newValue, lastValue, deadband) {
// 死区为0.5%,变化超过0.5%才存储
return Math.abs(newValue - lastValue) / lastValue > deadband;
}
我曾经在一个工厂项目中用了这个策略,数据量直接减少了60%。而且对分析结果几乎没有影响——因为微小的波动本来就不重要。
注意:死区压缩不适合计费数据。计费要求精确到小数点后两位,任何数据都不能丢。所以,计费数据单独存,不做任何有损压缩。
4.4 整体架构图
下面这张图,是我做过的某个EMS项目的存储架构。你一看就明白了。
这张图里,数据从采集层进来,先经过消息队列缓冲,然后分三路存储:
- 时序数据库:存实时数据和降采样数据,供监控和短时分析
- 关系型数据库:存设备信息和用户配置,供业务系统查询
- 对象存储:存超过3个月的历史归档,压缩后存成Parquet文件,成本极低
一个小技巧:对象存储里的历史数据,可以用Apache Parquet格式存。Parquet是列式存储,压缩比高,而且支持按列读取。我试过,同样的数据,Parquet比CSV小了80%,查询速度还快了10倍。
好了,数据存储这块就聊到这儿。选型没有绝对的对错,关键看你的场景。电表数量少,InfluxDB省心;数量大、要求高,TDengine更香。关系型数据库老老实实存元数据,别越界。压缩策略用好了,存储成本能降一大半。
记住一句话:数据是能源管理的血液,存储方案就是血管。血管堵了,整个系统都得瘫痪。
公众号:蓝海资料掘金营,微信deep3321