跳到主要内容

数据入库、模型与查询验证

数据库目标从转发组接收数据。先确定要保存当前值、连续采样还是报警事件,再选择目标和模型;建好数据库连接并不意味着点位已经进入存储范围。

先完成一次入库​

选择存储目标​

需求使用的目标
每个变量只保留最新值实时数据存储,同一变量覆盖更新。
保存变化过程、定时采样和历史曲线历史数据存储,保存多条历史记录。
保存报警发生、确认和恢复历史报警存储,使用报警事件及其时间。

实时表不能还原已经被覆盖的历史过程;历史报警和普通变量历史也应分别查询。

先用两个点完成入库验证​

  1. 准备一个数值变量及一个字符串变量,确认它们的值和质量正常。
  2. 在“开发配置 → 数据转发”创建手动范围组,保存后把两个变量加入“转发变量”。
  3. 选择需要的触发方式。变化模式只记录变化;定时模式在稳定值下也生成快照。核对组内每行的更新覆盖配置。
  4. 添加历史数据目标,选择数据库类型,填写连接字符串、表名和时区。
  5. 保存并启用,等待目标初始化。在目标调试中查看管线、缓存与最近错误。
  6. 让数值和字符串各改变一次,分别检查对应历史表,再到“数据与告警 → 数据查询 → 历史数据”核对。

使用 SQLite 练习时,可填写独立文件,例如 Data Source=DB/history-demo.sqlite;journal mode=WAL。路径相对于运行网关的目录,需要具备写入权限;多个目标应明确各自文件或表名。

数据库与数据模型​

数据库与模式的组合​

数据库或模型选择与限制
SQL Server、MySQL、SQLite、PostgreSQL支持关系型标准表、自定义 SQL,以及对应的表脚本。标准模式下数值、字符串和变量信息分别存储。
QuestDB使用原生连接和时间列;保留策略使用原生 TTL。自定义宽表需匹配其建表和写入语法。
TDengine使用原生数据库和保留策略。连接协议、端口和数据库关键字必须配套,详见目标页。
IoTDB Table连接串填写 Model=table;Database=...。支持标准表模型或自定义 SQL 宽表。
IoTDB Tree连接串填写 Model=tree;RootPath=...。按设备路径及 measurement 存储,不使用自定义 SQL 宽表。

IoTDB 的 Table 与 Tree 是不同物理模型,不能同时填写 Database 和 RootPath。关系库使用“历史表脚本”,QuestDB、TDengine、IoTDB 使用“时序历史脚本”;脚本模式与自定义 SQL 模式互斥。

IoTDB 配置和核对​

以 Table 模型为例:

DataSource=127.0.0.1;Port=6667;Username=root;Password=<密码>;Model=table;Database=tgateway_history;PoolSize=8;FetchSize=1024;ConnectionTimeoutInMs=5000;PoolWaitTimeoutInMs=10000;Compression=false;ZoneId=UTC;UseSSL=false
  1. 将地址、端口、账号和库名替换为实际配置,先关闭自定义 SQL 验证标准写入。
  2. 保存目标,确认数值、字符串分别进入对应表,并使用数据库客户端检查实际列类型。
  3. 改变源值,在网关查询中确认新增记录,不只查看初始记录或累计总数。
  4. 需要自定义宽表时,再在 Table 模型启用自定义 SQL,并按模板列映射验证。
  5. 启用 TLS 时按下方步骤分别配置服务端信任与客户端证书。文件位于运行网关的主机,不能照搬浏览器电脑上的路径。

IoTDB 历史数据查询中显示变化前后数值及新的采集时间

连接池、获取批量、压缩和超时影响连接与读取开销;修改这些参数不会把 Tree 变成 Table,也不会自动改变宽表列。

对照 Table 与 Tree 的物理结果​

项目Table 标准模型Tree 标准模型
数据位置Database 下的数值表与字符串表。RootPath.device_设备ID 下的测点。
变量标识device_id、variable_id 为字符串 TAG。数值使用 n_变量ID,字符串使用 s_变量ID,不要根据显示名称猜路径。
值与质量value 为 STRING;is_number、is_online 为 BOOLEAN。网关数值查询会转换数值文本。保存时间和值,标准路径不额外保存设备名称、变量名称和质量字段。
时间内置 time,以及毫秒整数 collect_time、create_time。测点的时间戳。
自定义宽表支持,按列配置或显式 SQL 写入。不支持自定义 SQL 宽表。

修改数据库名、表名或根路径后,查询新位置中保存之后的样本,同时保留旧位置作对照。旧样本不会自动移动。数值成功后还要单独改变字符串,确认两类数据都走到新位置。

Table 和 Tree 的账号权限分别配置。Table 的表权限不能代替 Tree 的路径读写及 schema 权限;需要自动建库、建表或建测点时,还要核对相应创建权限。

连接参数的实际作用​

参数使用说明
NodeUrls逗号分隔的 主机:端口 引导列表。配置后应优先核对列表入口,避免只修改 Port 却仍连接列表中的地址。
PoolSize当前目标的池连接上限,与变量数量无关。实际并发还受池大小和数据库负载限制。
FetchSize查询分批抓取行数,不是查询总行数上限;设为 1 仍可通过多次抓取返回一整页。
ConnectionTimeoutInMs建立原生连接的等待上限,单位毫秒。
PoolWaitTimeoutInMs借用池连接的等待上限,单位毫秒。增加等待时间不会增加数据库容量。
CompressionRPC 传输压缩,必须与 IoTDB 服务端配置一致;不是字段编码或历史保留策略。
ZoneId会话时区。标准写入使用 UTC 绝对毫秒时间;目标通用“时区偏移”不会给标准样本整体平移八小时。

IoTDB 不使用关系库分表策略、变量信息表和关系型双库镜像。选择按日分表不会生成日期后缀表,开启双库字段也不会使 IoTDB 成为受支持的镜像主库。

Table 宽表与脚本​

先用 reading(DOUBLE)映射数值变量、status(STRING)映射字符串变量,再用 origin(STRING)映射一个不存在的变量,默认值设为 gateway。不分组时每个变量独立成行;按设备分组时,现场设备和 Memory 设备仍分别成行。需要按备注分组时,先在真实输入变量上填写相同的备注。

IoTDB 自动宽表固定使用内置 time(TIMESTAMP),并建立 group_key 标签;通用“时间列名”“时间列类型”不会改变该物理列。自动建表也不根据 IsRequired 创建非空约束,不能据此保证缺值行一定被拒绝。需要约束时应按数据库实际能力设计显式 SQL 和输入校验。

改用时序历史脚本前关闭自定义 SQL。脚本定义自己的 schema 和清理策略,标准历史查询不能自动解释任意脚本表结构,应准备对应的查询方式。保留天数必须结合实际清理语句核对,不能以保存配置代替旧数据已经清除。

IoTDB TLS 配置​

  1. 确认 IoTDB 入口支持 TLS,地址、端口和证书中的服务名称匹配。
  2. 在网关运行账号使用的系统信任存储中建立对服务端签发 CA 的信任;同时满足证书有效期和吊销检查要求。
  3. 连接串填写 UseSSL=true;CertificatePath=...。CertificatePath 传给客户端证书配置,不负责导入服务端 CA 信任;公开证书文件也不能证明客户端持有私钥。
  4. 保存目标后查询新样本。Table 与 Tree 分别验证,不能用一种模型的旧数据证明另一种模型已经连通。
  5. 遇到不受信任、证书文件不存在或无权限时,分别检查系统信任、路径及运行账号权限,修正后再查询保存之后的新记录。

TLS 验证中应持续启用证书、名称与吊销校验。恢复普通连接时同步核对端口和 TLS 开关,避免加密客户端连到明文 RPC 入口。

标准表、脚本与宽表​

配置核对重点
标准表使用目标的数值、字符串和变量信息表名。核对变量身份、值、质量及时间。
关系型表脚本为四种关系库选择动态 SQL 脚本,确认建表、批量写入和保留清理均符合当前数据库。
时序历史脚本为 QuestDB、TDengine、IoTDB 选择时序库逻辑脚本,按脚本自己的表结构验证实际写入。
自定义 SQL 宽表明确表名、时间列、各列类型与变量映射。查询结果使用实际列名,不能套用标准表的固定列。
分表关系库按配置的时间策略组织物理表。查询跨期数据时检查相应分表是否存在。
保留天数控制历史保留或清理。改变保留周期后,需要观察实际清理任务,不能仅靠配置读回判断旧记录已删除。

数值、字符串和离线数据的路由应分别验证。某一条数值成功写入,并不能说明字符串表、自定义列和报警表也已正确配置。

更改数据库类型、连接或表名只影响后续写入,不会迁移旧历史。关系库“自定义”分表依赖已部署的分表服务,不能仅在页面选择该项就生成任意后缀。

验证 QuestDB 与 TDengine​

QuestDB 使用 HTTP REST SQL/CSV,默认端口 9000,不能填写 PostgreSQL 协议端口。标准模式分别保存数值和字符串,查询前从表结构核对指定时间戳列。TDengine WebSocket 连接使用 Protocol=WebSocket;Port=6041;db=...;Native 使用 6030 并需要原生客户端库,数据库键使用小写 db。

先验证标准结构,再绑定时序脚本,查询脚本表中的新数值与字符串。QuestDB 核对时间列和分区;TDengine 核对超级表、每变量子表及标签。脚本清空后,确认标准表重新接收新样本,旧脚本表仍保留。详细操作见绑定时序历史脚本。

时间与可靠性​

区分三个时间​

时间用途
采集时间 CollectTime来源采样时间。用于判断数据新鲜度以及回看离线期间的过程。
变化时间 ChangeTime值发生变化的时间。定时快照的值未变化时,这个时间可能早于采集时间。
记录时间 CreateTime转发组生成记录的时间。标准关系表按此列分表,部分原生历史模型也使用它作为主记录时间。

目标“时区偏移”属于存储约定。带 Z 的时间表示 UTC;本地墙钟值应按目标配置解释,不能再重复增加八小时。查询、图表、导出和数据库客户端应采用一致的时区和时间列。

可靠性与双库镜像​

历史目标启用失败重试缓存后,数据库不可用期间的待写记录可在恢复后补写;实时目标等待新的变化或快照覆盖最新值。缓存容量、历史保留天数和数据库镜像分别控制不同环节。

关系库标准历史模式可按目标页配置双库镜像。主、备用库应为不同物理库,且都属于支持的关系库;自定义 SQL、历史表脚本及原生时序库不能直接套用该镜像配置。

启用镜像后,分别核对主库写入、待同步积压、备用库内容及差异检查。主目标在线并不能单独证明备用库已完成同步。

在“目标调试 → 双库检查与修复”中,按 CreateTime 选择时间范围,分别检查数值、字符串及两个同步方向,先检查再补齐,随后重复检查同一范围。新备用库不会自动回填全部旧历史;取消维护也不会撤回已经完成的分片。范围及幂等补齐说明见双库维护。

区分重复记录与内容冲突​

关系库标准历史模式的可靠写入按 RecordKey 识别同一条记录。同键且核心内容相同,按重复处理;同键却有不同的变量身份、值或采集时间,会明确报告冲突。同一输入批次中的重复也按此规则检查,不会把不同内容静默算作已保存。

现象核对方法
重试后新增数量少于输入数量查询同一记录键,确认数据库已有记录的变量、值和时间与输入一致。
日志提示 RecordKey 冲突保留原数据,检查主备来源、重复生成逻辑及时间和值是否一致。修正冲突原因后再重试。
一批写入失败查看目标日志及实际表内容,按原记录范围核对;不要仅凭批次提交或缓存计数判定所有记录已写入。

来源节点、提交批次等附加元数据的差异不等于业务内容冲突。上述规则用于标准关系库历史记录,脚本、自定义 SQL 和原生时序模型应按各自的写入约定验证。

查询与导出验收​

  1. 选择正确的 组名/目标名,缩小到单个变量和明确时间窗口。
  2. 按最新时间排序,核对新增值、采集时间、记录时间和质量。
  3. 曲线至少覆盖一次上升和下降,并与表格记录对照。
  4. 导出当前页,检查实际文件行数;其他页需要分别导出。页面总数不代表本次文件行数。
  5. 数据库异常恢复后,确认旧采样补齐及积压回落,再核对新的正常采样。

查询步骤与分页见数据查询,断线验证见离线缓存与补传。