时序数据库教程

从零理解:什么是时序数据库、怎么用、什么场景该用

0. 什么是时序数据 1. 数据模型 2. 生活化场景 3. 写入数据 4. 查询数据 5. 聚合降采样 6. 连续查询 7. 保留策略 8. 选型指南

0. 什么是时序数据?

一句话:带时间戳的数据,按时间顺序不断追加

你身边到处都是:

MySQL — 通讯录思维

张三的薪资从15000改成18000,旧值就没了。关注的是当前状态

UPDATE employees SET salary = 18000 WHERE name = '张三';

15000 这个历史值消失了

时序数据库 — 心电图思维

每秒追加一条新记录,从来不改旧数据。关注的是变化趋势

temperature,host=server1 value=36.5 1700000000
temperature,host=server1 value=36.8 1700000001
temperature,host=server1 value=37.1 1700000002

三个值都保留,画出一条线

一句话记忆:MySQL 改数据(UPDATE),时序库追数据(INSERT ONLY)。MySQL 问"现在是啥",时序库问"最近怎么变"。
同一个需求,两种数据库的思路对比
需求MySQL 怎么做时序库怎么做
记录服务器CPUINSERT 一条,下次 UPDATE 覆盖每次 INSERT 追加一条,永不覆盖
查当前温度SELECT 最新那一行SELECT LAST(value)
查最近1小时平均需要额外表存历史,再 AVGMEAN(value) WHERE time > now() - 1h
清理旧数据DELETE WHERE time < ...(慢)自动过期,配置保留策略即可
每秒写入量几百到几千行/秒就吃力几十万到百万行/秒很轻松

1. 数据模型:时序数据长什么样?

时序数据库的一条数据由三部分组成:

一条时序记录的结构:

时间戳 (timestamp) + 测量值 (field/value) + 标签 (tag)

时间戳:这条数据是什么时候产生的(必须有)
测量值:你要记录的数字,比如温度36.5、CPU 85%
标签:描述性信息,比如哪台机器、哪个机房(用于筛选分组)

用图书馆来类比就很好懂了:

图书馆每笔借书单 = 一条时序数据
时间戳测量值(field)标签1:门店标签2:品类标签3:规格
2024-06-01 10:00金额=18门店=朝阳店品类=图书馆规格=大杯
2024-06-01 10:02金额=22门店=海淀店品类=图书规格=标准
2024-06-01 10:05金额=15门店=朝阳店品类=咖啡规格=小杯
2024-06-01 10:08金额=28门店=朝阳店品类=图书馆规格=大杯
2024-06-01 10:12金额=18门店=海淀店品类=图书馆规格=标准
标签 vs 测量值的区别:
标签 = 用来筛选/分组的维度(WHERE 和 GROUP BY 的字段),字符串类型
测量值 = 用来计算的数字(SUM/AVG/MAX 的字段),数值类型
简单记:标签划圈,测量值算数

2. 生活化场景:什么时候该用时序数据库?

🏠 智能家居最典型

温湿度传感器每5秒上报一次,你要看"客厅最近24小时温度曲线"

数据特点:写入频繁、不改历史、按时间查趋势

📊 服务器监控最典型

每台机器每秒报CPU/内存/磁盘,几十台机器 = 几百数据点/秒

数据特点:海量写入、实时聚合、自动过期

🚗 车联网/物联网常见

每辆车每秒报GPS位置、车速、油耗,百万辆车 = 百万点/秒

数据特点:超大规模写入、按车辆分组、轨迹回放

💰 金融行情常见

股票/币价每秒甚至每毫秒一个价格,K线图需要按分钟聚合

数据特点:极高频率、降采样需求强

🏪 连锁门店销售可以用

每笔借书单带时间戳,分析"哪个时段、哪个门店、哪个品类卖得好"

数据特点:有标签(门店/品类)、有测量值(金额)

🏃 健身/运动追踪可以用

手环每秒记心率、步数,App展示"本周运动趋势"

数据特点:个人数据量不大,但用户量多时总量惊人

什么时候不该用时序数据库?
- 要频繁 UPDATE 单条记录(比如改用户密码)→ 用 MySQL
- 数据之间没有时间维度(比如通讯录)→ 用 MySQL
- 需要 JOIN 多表(时序库一般不支持 JOIN)→ 用 MySQL
- 事务一致性要求高(比如转账)→ 用 MySQL

3. 写入数据(以 InfluxDB 为例)

InfluxDB 是最流行的时序数据库,它的写入语法叫 Line Protocol,一行就是一条数据:

-- 语法格式:
测量名,标签1=值1,标签2=值2 字段1=值1,字段2=值2 时间戳

-- 图书馆例子:
orders,store=朝阳店,category=图书馆,size=大杯 amount=18 1717203600000000000
orders,store=海淀店,category=图书,size=标准 amount=22 1717203720000000000
orders,store=朝阳店,category=咖啡,size=小杯 amount=15 1717203900000000000
拆解一行数据(对应上面的数据模型)
部分内容含义
测量名orders类似 MySQL 的表名
标签store=朝阳店, category=图书馆, size=大杯类似 MySQL 的维度列,用于 WHERE / GROUP BY
字段amount=18类似 MySQL 的数值列,用于 SUM / AVG / MAX
时间戳1717203600000000000纳秒级 Unix 时间戳,这条数据的时间
标签 vs 字段 一定要分清:把经常用来筛选/分组的设为标签(索引,查询快),把只用来计算的数字设为字段(不索引,但能聚合)。如果你把"金额"设成标签,想 SUM(amount) 就做不到了。

4. 查询数据(InfluxQL / Flux)

InfluxDB 的查询语言叫 InfluxQL,语法跟 SQL 非常像,但专门为时序数据优化了。

4.1 基础查询

-- 查所有借书单
SELECT * FROM orders

-- 查朝阳店的借书单
SELECT * FROM orders WHERE "store" = '朝阳店'

-- 查最近1小时的借书单
SELECT * FROM orders WHERE time > now() - 1h

-- 查朝阳店最近30分钟的图书馆借书单
SELECT * FROM orders
WHERE "store" = '朝阳店' AND "category" = '图书馆' AND time > now() - 30m
朝阳店最近30分钟的图书馆借书单(假设当前 10:30)
timestorecategorysizeamount
2024-06-01 10:00:00朝阳店图书馆大杯18
2024-06-01 10:08:00朝阳店图书馆大杯28
2024-06-01 10:22:00朝阳店图书馆标准15
3 rows

4.2 聚合查询(跟 MySQL 的 GROUP BY 很像!)

-- 每个门店的总销售额
SELECT SUM(amount) FROM orders GROUP BY "store"

-- 每个品类的平均借书单金额
SELECT MEAN(amount) FROM orders GROUP BY "category"

-- 每个门店+品类的借书单数和总额
SELECT COUNT(amount), SUM(amount) FROM orders GROUP BY "store", "category"
每个门店的总销售额
storeSUM(amount)
朝阳店133
海淀店91
2 rows
每个门店+品类的借书单数和总额
storecategoryCOUNTSUM
朝阳店图书馆361
朝阳店咖啡115
朝阳店图书257
海淀店图书馆233
海淀店图书238
海淀店咖啡120
6 rows
跟 MySQL GROUP BY 的区别:
MySQL: GROUP BY store — 按列分组
InfluxQL: GROUP BY "store" — 按标签分组(标签是预索引的,更快)
InfluxQL 还能 GROUP BY time(1h) — 按时间段分组(MySQL做不到!)

5. 聚合 + 降采样(时序数据库的杀手锏)

这是时序数据库最强大的功能,MySQL 很难做到:

5.1 按时间段聚合

-- 每小时的销售额(按1小时切分)
SELECT SUM(amount) FROM orders GROUP BY time(1h)

-- 每小时的每个门店销售额
SELECT SUM(amount) FROM orders GROUP BY time(1h), "store"

-- 每10分钟的借书单数
SELECT COUNT(amount) FROM orders GROUP BY time(10m)
每小时的销售额(假设一天的数据)
时间区间SUM(amount)💡 说明
2024-06-01 08:00958点-9点所有借书单金额加总
2024-06-01 09:001329点-10点所有借书单金额加总
2024-06-01 10:0015810点-11点所有借书单金额加总
2024-06-01 11:0011011点-12点所有借书单金额加总
4 rows

5.2 降采样 = 降精度省空间

原始数据是每5秒一条,查1年趋势图 = 630万条数据,浏览器都画不出来。怎么办?

MySQL 的笨办法

1. 原始表每5秒一条,1年 = 630万行

2. 查询时临时聚合:GROUP BY DATE_FORMAT(time, '%Y-%m-%d %H:00')

3. 每次查询都要扫描630万行再聚合,很慢

时序库的聪明做法

1. 用连续查询自动把5秒数据聚合成1小时数据,存到另一张表

2. 查趋势时直接查1小时表,1年 = 8760行

3. 查询速度快几百倍,存储还更省

降采样过程示意
阶段精度1年数据量用途
原始数据5秒一条6,307,200 行查最近几分钟的详情
1分钟聚合1分钟一条525,600 行查最近几小时
1小时聚合1小时一条8,760 行查最近几天的趋势
1天聚合1天一条365 行查月度/年度报表

6. 连续查询(自动聚合,不用手动跑)

连续查询 = 定时自动执行的聚合查询,把原始数据的结果写到另一张表里。

-- 创建连续查询:每30分钟把原始借书单聚合成1小时统计
CREATE CONTINUOUS QUERY cq_orders_1h ON milk_tea_db
RESAMPLE EVERY 30m
BEGIN
SELECT SUM(amount) AS total,
COUNT(amount) AS cnt,
MEAN(amount) AS avg_amount
INTO orders_1h -- 结果存到这张表
FROM orders -- 从原始表读
GROUP BY time(1h), "store", "category"
END
自动生成的 orders_1h 表内容
timestorecategorytotalcntavg_amount
2024-06-01 08:00朝阳店图书馆95519.0
2024-06-01 08:00海淀店图书82420.5
2024-06-01 09:00朝阳店图书馆132718.9
2024-06-01 09:00海淀店图书76325.3
4 rows — 自动更新,不用手动跑
类比:连续查询就像 MySQL 的 Event(定时任务),但内置在时序数据库里,不用额外部署。每30分钟跑一次,把5秒精度的数据"浓缩"成1小时精度,后续查趋势直接查 orders_1h 就行。

7. 保留策略(自动过期旧数据)

时序数据量增长很快,不可能永远存着。保留策略 = 自动删除N天前的数据

-- 创建保留策略:原始数据保留30天
CREATE RETENTION POLICY rp_30d ON milk_tea_db
DURATION 30d REPLICATION 1 DEFAULT

-- 聚合数据保留1年
CREATE RETENTION POLICY rp_1y ON milk_tea_db
DURATION 365d REPLICATION 1
数据生命周期(搭配连续查询 + 保留策略)
数据层级保留策略精度存多久查询场景
原始数据rp_30d5秒30天最近几分钟的实时监控
1分钟聚合rp_30d1分钟30天最近几小时的详情
1小时聚合rp_1y1小时1年最近几天的趋势图
1天聚合rp_1y1天1年月度/年度报表
对比 MySQL:MySQL 要手动写 DELETE WHERE time < '30天前',而且 DELETE 大量数据会导致表锁、性能下降。时序库的保留策略是后台静默自动完成的,零影响。

8. 选型指南:MySQL vs 时序库 vs 其他

8.1 决策表

你的需求MySQL时序库 (InfluxDB/TDengine)说明
每秒写入 < 100条✅ 够用✅ 也行量小的话 MySQL 就够了
每秒写入 > 1000条❌ 吃力✅ 轻松时序库的写入是 MySQL 的 10-100倍
需要 JOIN 多表✅ 强项❌ 不支持时序库基本不能 JOIN
需要事务 (ACID)✅ 强项❌ 不支持转账、下单必须用 MySQL
查趋势/时间范围⚠️ 能做但慢✅ 专门优化时序库按时间索引,极快
自动过期旧数据❌ 需手动✅ 内置时序库配个保留策略就行
降采样/预聚合❌ 需自己写✅ 连续查询时序库自动完成
频繁 UPDATE 单条✅ 强项❌ 不适合时序数据几乎不 UPDATE

8.2 主流时序数据库对比

常见时序数据库选型
数据库语言/产地查询语言特点适用场景
InfluxDB美国/开源InfluxQL / Flux最流行,社区大,云托管方便通用监控、IoT、运维
TDengine中国/开源类SQL超快写入速度,中文文档好工业IoT、车联网、金融
TimescaleDB美国/开源标准SQLPostgreSQL扩展,SQL兼容已有PG经验、需要SQL生态
Prometheus开源/CNCFPromQLK8s监控标配,拉模式采集容器/云原生监控
QuestDB开源SQL超快,零依赖,适合嵌入式金融行情、高性能场景

8.3 一句话选型

决策流程

  1. 你的数据有没有时间维度?没有 → MySQL
  2. 你会频繁 UPDATE 单条记录吗?会 → MySQL
  3. 你需要 JOIN 多表吗?需要 → MySQL 或 TimescaleDB
  4. 写入量每秒 < 100条?是 → MySQL 也行,时序库也行,看团队熟悉度
  5. 写入量每秒 > 1000条?是 → 必须时序库
  6. 需要自动过期降采样?是 → 时序库
  7. 已有 PostgreSQL 经验?→ TimescaleDB(学习成本最低)
  8. 中国团队、中文文档?→ TDengine
  9. K8s 监控?→ Prometheus(行业标配)

总结速查

时序数据库核心概念一张表

概念一句话MySQL 类比
时间戳每条数据必须有,代表"什么时候发生的"DATETIME 列
标签 (tag)描述性维度,用来筛选分组(索引)WHERE / GROUP BY 的列
测量值 (field)数值,用来聚合计算SUM / AVG 的列
测量名 (measurement)一类时序数据的名字表名
降采样5秒→1分钟→1小时,精度降低但省空间手动 GROUP BY + INSERT 到另一张表
连续查询定时自动聚合,结果写到另一张表Event / cron 定时任务
保留策略数据自动过期,N天后删除手动 DELETE + 写脚本
一句话记忆:时序数据库 = 不改只追 + 按时间索引 + 自动过期 + 自动降采样。
什么时候用?数据有时间维度 + 写入量大 + 不改历史 + 要看趋势 → 时序库。
什么时候不用?要改数据、要 JOIN、要事务 → MySQL。