第4章:时序数据库选型与设计

各位同学好,今天我们来聊聊风电功率预测系统里一个非常关键的底层组件——时序数据库。说实话,我见过不少项目,算法模型做得漂漂亮亮,结果数据存取的环节拖了后腿,整个系统响应慢得像蜗牛。嗯,这章我们就来把这个坑填上。

4.1 为什么风电系统离不开时序数据库?

风电功率预测,说白了就是跟时间序列数据打交道。风机每秒钟产生的风速、风向、转速、功率数据,都是带时间戳的。你想想看,一个风场几十台风机,一天下来就是几亿条数据。

传统的关系型数据库,比如MySQL,存这种数据其实很吃力。我曾在项目里试过用MySQL存风电数据,结果查询一个月的趋势图,等了十几秒才出来。后来换成时序数据库,同样的查询,毫秒级响应。为什么会这样?因为时序数据库从底层设计上就是为这种场景优化的。

核心观点:时序数据库是风电功率预测系统的数据基石。选对了,事半功倍;选错了,后面全是坑。

4.2 三大时序数据库对比

目前市面上主流的时序数据库,我重点用过三个:InfluxDB、TimescaleDB、TDengine。每个都有自己的脾气,我们来逐个聊聊。

特性 InfluxDB TimescaleDB TDengine
底层存储 自研TSM引擎 基于PostgreSQL 自研时序引擎
写入性能 高(单机百万点/秒) 中(依赖PG优化) 极高(千万点/秒)
查询语法 类SQL(Flux/InfluxQL) 标准SQL 类SQL(有限支持)
集群能力 企业版支持 原生支持 原生支持
学习成本 中等 低(熟悉PG即可) 中等
适用场景 中小规模监控 需要复杂关联查询 大规模工业物联网

4.2.1 InfluxDB:灵活但有点“娇气”

InfluxDB是我最早接触的时序数据库。它的数据模型很灵活,tag、field、timestamp三层结构,写起来很顺手。我个人习惯用它做原型验证,因为部署简单,一条命令就能跑起来。

但是,我在项目中遇到过一个问题:InfluxDB的单机版在高并发写入时,容易触发压缩瓶颈。有一次现场数据量突增,写入延迟从毫秒级飙升到秒级,差点影响预测系统的实时性。后来我们加了写入缓冲层才解决。

小技巧:用InfluxDB时,tag的基数不要太大。我建议控制在100万以内,否则索引性能会急剧下降。

4.2.2 TimescaleDB:SQL党的最爱

TimescaleDB本质上是PostgreSQL的一个扩展。如果你团队里都是SQL高手,那选它准没错。标准SQL写起来就是爽,join、子查询、窗口函数随便用。

我记得有一次做风功率预测的特征工程,需要把风速数据和气象预报数据做时间对齐。用TimescaleDB的time_bucket函数,一行SQL就搞定了。换成InfluxDB,得写一堆Flux脚本,麻烦得很。

不过,TimescaleDB的写入性能相比原生时序库还是弱一些。它底层还是PG的那套行存机制,虽然加了自动分区,但写吞吐量上不去。我建议数据量在每天10亿条以下的场景用TimescaleDB,再大就得考虑别的了。

4.2.3 TDengine:国产之光,但生态尚浅

TDengine是涛思数据的产品,我这两年用得比较多。它的设计理念很对我胃口——一个数据采集点一张表,超级表做聚合。这种模型跟风电场景天然契合:每台风机一张子表,整个风场一个超级表。

性能方面,TDengine确实猛。我做过压测,单机写入速度能到每秒800万点,查询一个月的聚合数据,基本在100毫秒以内。而且它对ARM架构支持很好,我们有些边缘节点用树莓派跑TDengine,稳得很。

注意:TDengine的SQL语法跟标准SQL有差异,比如不支持完整的JOIN操作。如果你的查询逻辑特别复杂,可能需要做一层数据预处理。

4.3 数据模型设计

数据模型设计,说白了就是怎么组织你的数据。我总结了一个“三要素”原则:

  • 时间戳:统一用UTC时间,避免时区问题。我习惯用毫秒级精度,够用又不浪费存储。
  • 标签:风机ID、机组型号、风场ID这些不变的信息。标签会被索引,所以基数要控制好。
  • 指标:风速、功率、转速这些数值。指标是实际存储的数据,会做压缩。

举个例子,在TDengine里创建超级表:

CREATE STABLE TABLE wind_turbine (
    ts TIMESTAMP,
    wind_speed FLOAT,
    power_output FLOAT,
    rotor_speed FLOAT,
    pitch_angle FLOAT
) TAGS (
    turbine_id INT,
    wind_farm_id INT,
    model_type VARCHAR(20)
);

然后每台风机创建一张子表:

CREATE TABLE turbine_001 USING wind_turbine TAGS(1, 101, 'GW-1500');

这样设计的好处是,查询单台风机数据时,直接定位到子表,效率极高。我建议你按这个模式来,别把所有数据塞到一张大表里。

4.4 存储策略与保留策略

风电数据有个特点:越老的数据,价值越低。实时预测用最近一小时的数据,短期预测用最近一周,中长期预测才用到历史数据。所以,没必要把所有数据都存成一份。

我常用的策略是“分层存储”:

  • 热数据:最近7天,全精度存储,放在SSD上。
  • 温数据:7天到3个月,降采样到1分钟粒度,放在HDD上。
  • 冷数据:3个月以上,降采样到10分钟粒度,归档到对象存储。

在InfluxDB里,保留策略(Retention Policy)可以这样配:

CREATE RETENTION POLICY "hot_policy" ON "wind_db" DURATION 7d REPLICATION 1 SHARD DURATION 1h DEFAULT;
CREATE RETENTION POLICY "warm_policy" ON "wind_db" DURATION 90d REPLICATION 1 SHARD DURATION 1d;

TDengine则用自动建库时指定保留天数:

CREATE DATABASE wind_db KEEP 365 DAYS 10 BLOCKS 6;

避坑指南:我曾经在项目里把保留策略设得太短,结果做年度分析时发现历史数据已经被删了。后来我改成“保留+归档”双保险:数据库里保留3个月,同时每天把数据备份到廉价存储里。

4.5 数据压缩与分区

压缩和分区,是时序数据库性能的两大法宝。先说压缩。

时序数据有很强的规律性:风速不会从0突然跳到20,功率曲线也是平滑变化的。利用这个特点,时序数据库可以用差值编码、游程编码等算法,把数据压缩到原始大小的十分之一甚至更小。

我实测过,InfluxDB的压缩比大概在5:1到8:1之间,TDengine能做到10:1以上。你想想看,原来需要100TB的存储,压缩后只要10TB,成本省了多少。

再说分区。分区就是把数据按时间切分成小段,查询时只扫描相关分区,避免全表扫描。我建议按小时或天分区,具体看你的数据量。

在TimescaleDB里,创建分区表:

SELECT create_hypertable('wind_data', 'ts', chunk_time_interval => INTERVAL '1 day');

TDengine默认按10天一个文件块分区,你也可以调整:

CREATE DATABASE wind_db DAYS 10;

我的经验:分区粒度不是越细越好。太细了,分区数量过多,元数据管理开销反而大。一般数据量在每天1亿条以下,按天分区就够了。超过这个量,可以考虑按小时分区。

4.6 本章小结

时序数据库选型,没有银弹。InfluxDB灵活,适合快速原型;TimescaleDB SQL兼容性好,适合复杂查询;TDengine性能强悍,适合大规模部署。我的建议是:先评估你的数据量和查询模式,再决定用哪个。

数据模型设计上,记住“时间戳+标签+指标”的三要素。存储策略要分层,保留策略要留余地。压缩和分区是性能的关键,一定要用好。

嗯,这章就讲到这里。下一章我们会聊数据采集层的设计,包括如何从风机PLC、SCADA系统里高效地拿到数据。到时候见。


公众号:蓝海资料掘金营,微信deep3321