跳到主要内容

历史数据存储

保存变量历史,用于查询过去的值和趋势。第一次练习可使用 SQLite 文件,不需要另外安装数据库服务器。

先把一个值存到本机

  1. 打开“开发配置 → 数据转发”,新增转发组 Demo_History_Group
  2. 变量范围选择“手动选择”,触发模式选择“定时”,定时间隔填 1000,保存。
  3. 点击组名称右侧的编辑图标,在弹窗下方“转发变量”中搜索一个正常采集的变量,选中后点击加号。确认表格出现该变量,再点击底部“保存”。可以使用上一课的 Demo_Modbus_Device.Demo_Modbus_Value
  4. 选中这个组,新增目标 Demo_History_Target,插件选择“历史数据存储”。
  5. 切换到“插件属性”页签,按下表填写,其他配置保持默认。
配置项这次怎么填
数据库类型Sqlite
连接字符串Data Source=manual-demo.sqlite;journal mode=WAL
自定义SQL模式关闭
分表策略不分表
数值历史表名保持 historyNumberValue
字符串历史表名保持 historyStringValue
变量信息表名保持 variableInfo
历史表脚本留空
时区偏移本例保持 +08:00
历史双库同步不点击“新增”,本例只存一个数据库
  1. 点击“确定”,保持组和目标启用。目标应显示“在线”;组内应显示 1 变量,不要把目标上的“属性 0”误认为没有选变量。文件会建在网关运行目录,不是浏览器所在电脑;该目录必须允许网关写入。
  2. 等待几个采样周期,到“数据与告警 → 数据查询 → 历史数据”,选择 Demo_History_Target
  3. 选择“数值数据”和刚才的变量。在时间面板中设置覆盖采集时间的范围,点击面板“确定”,再点筛选栏的刷新图标。应出现记录;再切换“图表”看曲线。固定值的曲线是水平线,不是没有采集。

历史目标使用本机 SQLite 文件,其他参数保持默认

演示变量已存入数据库并可查询历史曲线

完整查询、曲线和导出步骤见数据查询

换用项目数据库

在目标属性中选择实际数据库类型,再填对应连接字符串。SQL Server、MySQL、PostgreSQL 等需要事先准备可访问的数据库服务与账号;SQLite 使用本机文件。

按项目确定独立数据库或表名,账号需要建表、查询、插入及清理历史数据的权限。先用一个点写入成功,再增加变量。多数据库、自定义 SQL 和双库镜像配置在下方按需查阅,不是首次存储的前置步骤。

目标基本信息

参数默认值如何配置
所属转发组-必须选择已保存的转发组;目标只接收该组范围内的变量。
目标名称-必填,同一转发组内不能重复。建议包含数据库和环境名称,便于数据查询时区分目标。
启用开启关闭时目标不会启动,也不会写入历史数据。
插件-选择“历史数据存储”。保存后不要改成其它数据转发插件。
日志级别Info常规运行使用 Info;排查连接或写入问题时临时提高到 Debug,验证完成后恢复。
启动超时60目标初始化和数据库连接允许的最长时间,页面可填 13600 秒。
描述可填写环境、数据库用途或负责人,便于运维识别。

数据库存储

参数默认值如何配置
数据库类型SqlServer选择 SqlServerMySqlSqlitePostgreSqlQuestDbTDengineIoTDB。选择后必须使用对应连接串格式。
自定义SQL模式关闭关系型数据库、QuestDB、TDengine 和 IoTDB Table 可开启;IoTDB Tree 必须关闭。开启后使用“自定义模板配置”写入宽表。
分表策略不分表SQL Server、MySQL、SQLite、PostgreSQL 可按天、周、月、季度、年或自定义服务分表;自定义策略需要已部署对应分表服务。QuestDB、TDengine 和 IoTDB 使用各自原生存储策略,分表字段不会改变其原生表布局。
连接字符串server=.;uid=sa;pwd=111111;database=test;Encrypt=True;TrustServerCertificate=True;这是开发环境示例,生产环境必须替换为实际地址、数据库、账号和密码。可复制的各数据库示例见连接字符串
数值历史表名historyNumberValue标准模式下保存数值变量历史。关系型数据库、QuestDB、TDengine 和 IoTDB Table 会使用;自定义 SQL 模式改用模板中的 TableName
字符串历史表名historyStringValue标准模式下保存字符串变量历史。名称只能使用目标数据库允许的标识符。
变量信息表名variableInfoSQL Server、MySQL、SQLite、PostgreSQL 标准模式用于保存历史查询所需的变量信息;原生时序数据库通常不使用此表。
保留天数3650填写正整数。网关会将小于 1 的值归一为 1;清理任务按该值删除过期历史。QuestDB 使用 TTL,TDengine 使用 KEEP,IoTDB Table 使用删除任务。
历史表脚本仅 SQL Server、MySQL、SQLite、PostgreSQL 的关系型脚本模式使用。通过表达式选择器选择已保存的动态 SQL 脚本,由脚本负责建表、写入和清理;QuestDB、TDengine、IoTDB 的原生写入路径不接受该脚本。开启“自定义SQL模式”时不要同时填写。
时区偏移+08:00填写 +08:00-05:00 这类固定偏移;留空表示 UTC。写入和查询必须使用同一个约定,否则会出现时间相差数小时或无时区后缀的问题。
自定义模板配置仅“自定义SQL模式”使用。至少配置宽表名、时间列和需要写入的自定义列;三个 SQL 模板可以全部留空,由系统自动生成。
双库镜像关闭仅支持四种关系型数据库的标准历史表。需要主库和备用库同时写入时,打开后填写镜像配置;不能与自定义 SQL、历史表脚本或原生时序数据库组合。

连接字符串

下面的示例均使用独立数据库 thingsgateway_history。将 <密码>、地址和账号替换为实际值后,完整粘贴到“连接字符串”输入框。

数据库可直接修改的连接字符串说明
SQL ServerServer=127.0.0.1,1433;Database=thingsgateway_history;User Id=history_user;Password=<密码>;TrustServerCertificate=True;默认端口 1433。账号需要建表、读写和清理权限。
MySQLServer=127.0.0.1;Port=3306;Database=thingsgateway_history;Uid=history_user;Pwd=<密码>;Allow User Variables=true;AllowLoadLocalInfile=true;默认端口 3306。数据库名写在 Database
SQLiteData Source=DB/history.db;journal mode=WAL文件路径相对于网关运行目录;目录必须可写。journal mode=WAL 用于保持并发读写能力。
PostgreSQLHost=127.0.0.1;Port=5432;Database=thingsgateway_history;Username=history_user;Password=<密码>;默认端口 5432。自定义列使用 jsonjsonb 时,列类型必须与 PostgreSQL 一致。
QuestDBhost=127.0.0.1;port=9000使用 REST SQL,默认端口 9000。QuestDB 没有需要填写的 Database 命名空间,使用不同表名隔离目标;启用 TLS 时可加 UseSSL=true
TDengine WebSocketHost=127.0.0.1;Port=6041;Username=root;Password=<密码>;Protocol=WebSocket;db=thingsgateway_historyWebSocket 默认端口 6041。数据库键必须写小写 db=,不要写 Database=;协议必须写 Protocol=WebSocket
TDengine NativeHost=127.0.0.1;Port=6030;Username=root;Password=<密码>;Protocol=Native;db=thingsgateway_historyNative 默认端口 6030。运行环境还必须安装 TDengine Native 客户端库;无法安装时改用 WebSocket。
IoTDB TreeDataSource=127.0.0.1;Port=6667;Username=root;Password=<密码>;Model=tree;RootPath=root.thingsgateway;PoolSize=8;FetchSize=1024;ConnectionTimeoutInMs=5000;PoolWaitTimeoutInMs=10000;Compression=false;ZoneId=UTC;UseSSL=falseTree 必须有 Model=treeRootPath,不能填写 Database。模型由连接字符串决定。
IoTDB TableDataSource=127.0.0.1;Port=6667;Username=root;Password=<密码>;Model=table;Database=thingsgateway_history;PoolSize=8;FetchSize=1024;ConnectionTimeoutInMs=5000;PoolWaitTimeoutInMs=10000;Compression=false;ZoneId=UTC;UseSSL=falseTable 必须有 Model=tableDatabase,不能填写 RootPath。模型由连接字符串决定;只有 Table 可以使用自定义 SQL。

TDengine 连接串选项

TDengine 的连接串由 ; 分隔键值对组成。最少需要 HostPortUsernamePasswordProtocoldb。以下高级键可以按需追加:

示例作用
timezonetimezone=Asia/Shanghai驱动连接时区。
connTimeoutreadTimeoutwriteTimeoutconnTimeout=5000连接、读取和写入超时,单位由 TDengine 驱动解释。
useSSLuseSSL=true启用 TLS;服务端和证书配置必须匹配。
enableCompressionenableCompression=true启用传输压缩。
autoReconnectautoReconnect=true允许驱动自动重连。
reconnectRetryCountreconnectIntervalMsreconnectRetryCount=3;reconnectIntervalMs=2000设置重连次数和间隔。
tokenbearerTokentoken=<令牌>使用令牌认证时填写,不能与密码配置混淆。
adapterHAadapterHA=trueWebSocket 模式下启用 taosAdapter 实例发现和故障转移。

IoTDB 连接串选项

默认值配置说明
DataSourcePort127.0.0.16667IoTDB 节点地址和 RPC 端口。集群可额外配置 NodeUrls,例如 NodeUrls=10.0.0.11:6667,10.0.0.12:6667
Model必须是 treetable,直接决定历史 writer 使用的物理模型。
RootPath仅 Tree 使用,例如 root.thingsgateway
Database仅 Table 使用,例如 thingsgateway_history。Tree 和 Table 的 RootPathDatabase 互斥。
PoolSizeFetchSize81024连接池大小和查询抓取行数,必须为正整数。数据量较大时可提高 FetchSize,并观察内存。
Compressionfalse是否启用 RPC 压缩。
ZoneIdUTC服务端时区标识;要与数据查询的时区约定一致。
ConnectionTimeoutInMsPoolWaitTimeoutInMs500010000连接建立和连接池等待超时,单位毫秒,必须为正整数。
UseSSLCertificatePathfalse、空开启 TLS 时必须同时提供证书路径。

标准表与数据库模式

选择生成或使用的结构注意事项
SQL Server、MySQL、SQLite、PostgreSQL,关闭自定义 SQL数值表、字符串表和变量信息表可使用分表、历史表脚本和双库镜像。
SQL Server、MySQL、SQLite、PostgreSQL,开启自定义 SQL一张自定义宽表使用“自定义模板配置”;不要再填写历史表脚本。
QuestDB,关闭自定义 SQL数值表和字符串表使用 QuestDB 原生 REST/CSV 写入和表分区;使用不同表名隔离目标。
QuestDB,开启自定义 SQL自定义宽表时间列必须是 QuestDB 支持的时间列,查询按模板中的时间列排序。
TDengine,关闭自定义 SQL数值超级表、字符串超级表及变量子表SaveDays 映射为 KEEP;SplitTable 不改变 TDengine 表结构。
TDengine,开启自定义 SQL自定义超级表/子表宽表自定义建表 SQL 必须符合 TDengine 超级表语法;留空时由系统生成。
IoTDB Tree设备路径下的 measurement不使用自定义宽表和自定义 SQL;历史数据按设备路径查询。
IoTDB Table,关闭自定义 SQL标准表模型数值表和字符串表使用 TIME、TAG、ATTRIBUTE、FIELD;不使用 Tree 的 RootPath
IoTDB Table,开启自定义 SQLTable 模型自定义宽表只能在 Table 模型开启;历史查询页面按实际返回列展示。

IoTDB 的物理模型直接由连接串中的 Model 决定;RootPathDatabase 必须填写与模型匹配的选项,Tree 和 Table 不能混用。QuestDB、TDengine 和 IoTDB 使用各自的原生连接和写入方式。历史表脚本只适用于四种关系型数据库,且与自定义 SQL 模式互斥。

QuestDB 自动表使用原生分区和 TTL,TDengine 使用 KEEP;自定义建表或清理 SQL 填写后,以模板语句为准。IoTDB 的清理由目标清理任务执行。

自定义模板配置

开启“自定义SQL模式”后,在“自定义模板配置”中定义一行宽表如何容纳多个变量。三个 SQL 模板都可以留空;留空时系统按表结构、分组方式和列映射自动生成。

宽表字段

字段默认值如何配置
TableNameCustomHistoryData数据库中的实际宽表名。只能使用目标数据库允许的标识符,不能写成带密码或连接串的文本。
TimeColumnNameCollectTime每一行的时间列名。系统按该列查询、排序和清理;QuestDB、TDengine、IoTDB Table 还会把它映射到原生时间列。
TimeColumnTypedatetime填目标数据库支持的时间类型,例如 SQL Server datetime2、PostgreSQL timestamp、QuestDB TIMESTAMP
Columns空列表添加业务列。每列配置见下表;未添加列时宽表只有时间列,通常没有可写的业务值。
GroupModeCollectGroup选择按采集组、设备名称、备注1至备注5或“不分组”。同一分组和时间窗口内的变量会合并为一行。
GroupTimeWindowMs1000时间窗口,单位毫秒,必须大于 0。窗口越大,合并行越多;不分组时每个变量独立成行。
CustomInitSQL自定义建表 SQL。留空自动生成;填写后只替换初始化动作。
CustomInsertSQL自定义插入 SQL。留空自动生成;填写后只替换写入动作。
CustomDeleteSQL自定义清理 SQL。留空使用目标默认清理;填写后使用 SaveDays 对应的 {Days}

Columns 子项

字段如何配置
ColumnName数据库列名,不能重复,必须符合目标数据库标识符规则。
ColumnType数据库列类型,默认 nvarchar(200);也可使用 floatdoubledecimal(18,3)intbitvarchar(200)jsonjsonb。类型必须是当前数据库支持的类型。
VariableName优先匹配转发变量名称;也可填写 DeviceNameCollectGroupRemark1Remark5 读取设备或变量属性。留空时按 ColumnName 匹配同名变量。
DefaultValue找不到映射值时使用的默认值;留空则写入 NULL。默认值文本必须能转换为 ColumnType
IsRequired开启后自动建表生成 NOT NULL。若某次转发没有值且没有可用默认值,数据库会拒绝该行。

最小示例:添加 temperature 列,类型填 float,映射变量名填 Temperature;选择“按设备名称分组”,窗口填 1000。同一设备 1 秒窗口内的 Temperature 会写入同一行。

SQL 占位符

占位符只用于 SQL 结构,表名和列名会按目标数据库自动引用,数据值由参数或原生编码处理。不要把密码、Token 或完整连接串写入模板。

占位符可用于替换内容
{TableName}建表、插入、删除带数据库引用符的宽表名。
{TimeColumn}建表、插入、删除带数据库引用符的时间列名。
{Columns}建表所有自定义列的带引用符列名列表。
{ColumnNames}插入插入列清单,不包含时间列。
{TimeParam}插入时间参数名,通常为 @CollectTime
{ValueParams}插入自定义列对应的参数列表。
{UpdateSet}插入自定义列更新表达式,可用于支持 UPSERT 的方言。
{Days}删除当前目标的保留天数。

填写自定义 SQL 后,必须在目标日志和数据库客户端中各执行一次验证。不同数据库的引号、时间类型、UPSERT 和超级表语法不能互相套用。

双库镜像设置

参数默认值如何配置
同步到备用数据库关闭打开后主库和备用库都会写入标准历史表。
备用数据库类型SQL Server选择 SQL Server、MySQL、SQLite 或 PostgreSQL;不能选择 QuestDB、TDengine 或 IoTDB。
备用数据库连接填备用库完整连接字符串;主库和备用库必须是不同的物理数据库。
本机待同步上限262144本机镜像 Journal 的最大待提交记录数。
对端待同步上限1048576对端可见但尚未复制的最大记录数,不能小于本机待同步上限。
自动检查间隔(分钟)00 表示不启动定时一致性检查,最大 1440
自动补齐差异关闭一致性检查发现缺失记录时,是否自动双向补齐。启用前先确认两端权限和容量。

变量映射

该目标没有目标变量级附加属性。变量是否进入目标以及触发方式由转发组范围和组变量设置决定;保存目标后无需在“变量属性”侧栏重复配置。

转发组策略

历史目标不再配置目标级“默认采样策略”“采样间隔”或“条件表达式”。这些选项应在转发组编辑页设置;手动变量列表可以对单个组成员覆盖更新模式。

历史数据存储插件没有目标变量级的附加采样属性,不需要在“变量属性”中重复配置采样。

转发组参数默认值如何配置
变量范围手动选择全部变量手动选择采集设备采集组。范围决定哪些变量有资格进入历史目标。
范围配置选择采集设备或采集组时填写逗号分隔名称;全部和手动模式不使用此字段。
触发模式变化变化 在变量变化时触发,定时 仅由调度触发,定时或变化 两者都触发。
定时间隔1000可填毫秒数字(如 1000)或时间文本(如 00:00:01)。定时或变化模式下必须填有效间隔。
在线过滤关闭开启后组级先过滤离线变量;需要记录离线采集值时关闭。
分批模式不分批可选全部、按数据组、按设备或按采集组拆分一次触发的数据。
最大批量1000单次批处理允许的最大变量数量,范围 1100000

使用手动范围时,在组变量列表中还可以设置“启用”“数据组”“更新”“组触发”和“别名”。这些字段只影响该变量是否进入组、如何触发和如何命名,不会替代目标数据库连接配置。

缓存与容量

这些属性在“目标属性”页的“缓存与可靠性”或“容量限制”分组中设置。

参数默认值如何配置
启用失败重试缓存开启建议保持开启,数据库恢复后自动补发失败记录。关闭后,写入失败的数据不再保留重试。
缓存文件最大行数262144CacheDB 出站队列的最大行数。超过上限会删除最旧数据;按断网时长和写入速率预留磁盘空间。
上传分片大小2000每次写入或补发的最大记录数。数据库吞吐较低时减小,批量接口吞吐较高时可适当增大。
内存队列上限100000内存缓冲的最大记录数。超过后会尽早转入 CacheDB,仍超限时可能丢弃旧数据;不应按磁盘容量替代内存评估。
过滤离线数据关闭开启后,目标出队时过滤离线变量值。转发组也有同名在线过滤,只有两处都允许时数据才会进入目标。
并发上传数量1插件发送实现按需使用。历史目标默认串行上传;除非已确认数据库和网络可以承受,否则保持 1

目标调试

进入“开发配置 → 数据转发”,选择转发组和历史目标,打开“调试”。

功能作用
转发管线查看变量范围、触发模式、过滤结果和进入历史目标的数据摘要。
缓存出站查看内存队列、CacheDB 待处理数量、失败重试保留状态和最近错误。

转发管线

历史数据存储转发管线

“转发管线”用于确认变量范围、触发方式和进入目标的数据摘要。

缓存出站

历史数据存储缓存出站

“缓存出站”显示内存队列、CacheDB 待处理数量、保留重试数和最近错误。启用离线缓存后,数据库不可用期间的待写记录会在恢复后继续写入。

保存与验证

  1. 保存转发组和目标后,确认目标状态为“在线”,目标日志没有初始化错误。
  2. 让一个已纳入范围的变量产生一次变化,或等待一个定时周期。
  3. 在目标“调试”页查看“转发管线”和“缓存出站”。成功写入时,待处理数量应下降,最近错误应为空。
  4. 在数据库客户端查询最新记录,逐项核对变量标识、设备名、值、空值、采集时间和记录时间。自定义 SQL 模式还要核对模板中的每个列名。
  5. 在“数据查询 → 历史数据”中切换当前目标,确认总数、分页、最新排序和浏览器时区显示与数据库结果一致。

时间与查询

  • 时区偏移 是写入端的存储约定,不是浏览器时区设置。浏览器使用 Asia/Shanghai 时,若目标按 UTC 存储,接口可能返回带 Z 的 UTC 时间;若目标按 +08:00 存储,通常显示为本地墙钟值。两种结果表示的是同一时刻,关键是配置和查询使用同一偏移。
  • 标准模式使用固定的数值表和字符串表;自定义 SQL 模式按宽表实际列返回。不要用 variableIdvalue 等标准字段名去猜自定义宽表列名。
  • QuestDB、TDengine 和 IoTDB 原生模式可能使用原生时间列或整数时间戳。查询页应以返回列名和时间列类型为准,并检查最新行的所有字段。

常见问题

现象检查顺序
目标无法启动检查数据库服务、连接字符串键名和端口、账号权限、表名标识符、IoTDB 模型,以及是否错误地同时启用了互斥选项。
TDengine 提示找不到数据库确认连接串使用 db=数据库名,不是 Database=数据库名;WebSocket 使用 6041,Native 使用 6030,并确认 Protocol 与端口一致。
IoTDB 连接失败Tree 必须配置 Model=tree;RootPath=...,Table 必须配置 Model=table;Database=...;不要同时填写 RootPathDatabase。启用 TLS 时检查 CertificatePath
没有新增历史记录检查转发组变量范围、组是否启用、触发模式、定时间隔、组在线过滤和目标在线状态。历史目标没有单独的目标级采样配置。
数据库恢复后没有补写开启“启用失败重试缓存”,查看“缓存出站”的 CacheDB 待处理数量和目标日志。关闭缓存时,退避期间失败数据可能已被丢弃。
查询数量或最新时间不对先确认查询的目标名称和表名,再确认排序字段、时间范围、分表策略和时区偏移。自定义 SQL 模式按实际宽表列查询。
自定义 SQL 建表或写入失败检查 Columns 的列名、类型、映射变量和必填值;确认占位符、引号、时间类型和 UPSERT 语法符合当前数据库方言。
双库镜像保存失败检查备用连接、物理库是否与主库不同、两端是否都是关系型数据库,并确认未开启自定义 SQL 或历史表脚本。

相关操作

  • 数据转发:配置转发组、范围、触发、缓存、冗余和目标启停。
  • 历史数据查询:按目标查询标准历史表和自定义宽表,检查分页、排序和时区。
  • 插件手册索引:查找其它采集或数据转发插件。