时序数据库在物联网日志系统中的设计与实践:从数据结构到SpringBoot接入 一、一张表撑不住了 📌 前置知识:了解关系型数据库(RDBMS)基本概念,知道什么是SQL、索引、事务。知道什么是磁盘IO,理解顺序IO和随机IO的大致性能差距(约一个数量级)。
某开发者接手了一个物联网项目,设备每秒上报一次数据,1000台设备跑了一周,MySQL 的 iot_logs 表已经几千万行,查询一条设备最近一小时的数据要跑十几秒。加了索引,写入又慢得让人抓狂。这种场景,写过的都懂——关系型数据库不是不能存时序数据,而是它的每一个设计决策都和时序场景的需求背道而驰。
物联网日志(IoT Logs)具有几个典型特征:
写入密集且顺序:数据按时间顺序持续产生,极少更新或删除 查询模式固定:通常按时间范围 + 设备ID聚合查询,很少跨设备做复杂JOIN 数据冷热分明:最近几小时的数据被频繁访问,一周前的数据偶尔查一次 压缩空间巨大:传感器数据变化缓慢,相邻时间点数据高度相似,而 RDBMS 的通用压缩算法根本不认识这种模式 这就引出了一个核心问题:时序数据库(TSDB,Time Series Database)到底在数据结构层面做了哪些改造,让它和经典关系型数据库(RDBMS)产生了本质差异?以及如何在 Spring Boot 项目中把这些 TSDB 用起来?
二、数据结构层面的根本差异 2.1 行式存储 vs 列式存储 RDBMS 以 行(Row) 为单位组织数据,一行数据的各个字段在磁盘上连续存放。这种设计让单行读写非常高效——适合 OLTP 场景下"查一行、改一行"的套路。但面对时序查询时,问题就暴露了:查询"过去一小时内所有传感器的温度平均值",只需要温度这一个列,行式存储却会把湿度、气压、设备状态等几十个列一并从磁盘读进内存——IO 利用率奇低。
TSDB 采用 列式存储(Columnar Storage),将同一列的数据在磁盘上连续存放。查询温度列时,只读取温度相关的数据块,其他列完全不参与 IO。这和 ClickHouse 等 OLAP 引擎的思路一致,但 TSDB 在列式基础上又叠加了时间维度的特殊优化。
flowchart TD subgraph row["📦 行式存储 RDBMS"] direction TB r1["Row1│ts:1000│temp:25.3│hum:68│loc:WH1"] --> r2["Row2│ts:1001│temp:25.4│hum:67│loc:WH1"] r2 --> r3["Row3│ts:1002│temp:25.3│hum:68│loc:WH1"] end subgraph col["📦 列式存储 TSDB"] direction TB c_ts["Col_ts: 1000, 1001, 1002"] --> c_temp["Col_temp: 25.3, 25.4, 25.3"] c_temp --> c_hum["Col_hum: 68, 67, 68"] c_hum --> c_loc["Col_loc: WH1, WH1, WH1"] end row -.-> col classDef default fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#e5e7eb; classDef highlight fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#fecaca,font-weight:bold; class r1,r2,r3,c_ts,c_temp,c_hum,c_loc default class r1,c_temp highlight ⚠️ 新手提示:不要混淆"列式存储的数据库"和"时序数据库"。列式存储是 TSDB 的技术手段之一,但不是全部。ClickHouse 是列式存储的 OLAP 数据库,但它不是 TSDB——它没有时间维度的特殊处理(如自动分区、自动过期删除)。
...