从 MySQL 到时序数据库:我帮朋友做迁移的完整记录

大家好,我是小耶,写功课是为了我踩过的坑,你们别再踩了!

最近在帮朋友的公司做数据库架构升级。他们的场景是智能工厂的设备监控:200 多个传感器节点,每秒采集一次数据,包含温度、压力、振动等 5-10 个指标。之前用的 MySQL,单表已经膨胀到 8 亿行,写入延迟从毫秒级飙到秒级,磁盘空间也快到上限了。

朋友问了一个很直接的问题:"时序数据库是不是必须上的?还是说优化一下 MySQL 也行?"

这个问题让我翻了将近一周的资料。从各家的官方文档到 GitHub issue、社区帖子,再到一些实测数据,我发现一个有意思的现象:市面上关于时序数据库的文章,大部分要么是产品介绍,要么是概念科普。真正讲清楚"架构差异在哪里""什么场景用什么方案""迁移怎么做"的内容,并不多。

所以这篇我想从工程师的角度,把时序数据库的架构、性能数据和迁移路径拆开来讲。如果你正在做选型,或者已经在用但遇到了瓶颈,这篇应该有帮助。


一、时序数据库的架构本质

1.1 为什么传统数据库处理时序数据效率低?

传统关系型数据库的核心设计目标是 OLTP(在线事务处理):

  • ACID 事务保证
  • 随机读写均衡
  • 索引结构以 B+Tree 为主,适合点查和范围查询

但时序数据的特点是:

  • 写入模式:几乎全是 INSERT,极少 UPDATE/DELETE
  • 查询模式:按时间范围聚合(AVG/MAX/MIN/COUNT),不是精确查找
  • 数据生命周期:热数据(最近几小时)高频访问,冷数据(几个月前)几乎不读

用 OLTP 引擎处理时序数据,就像用轿车拉货------能用,但不专业。主要瓶颈在:

  • B+Tree 索引在大规模顺序写入时会频繁分裂,IO 放大
  • 行式存储导致聚合查询要扫描大量不需要的列
  • 缺乏自动降采样和保留策略,需要手动维护

1.2 时序数据库的存储架构

主流时序数据库的存储层有三种架构路线:

LSM-Tree 路线(InfluxDB 2.x、TDengine):

bash 复制代码
写入 → WAL(预写日志) → MemTable(内存缓冲) → SSTable(磁盘有序文件)
                                    ↓
                              后台 Compaction(合并)

优势:顺序写入,吞吐高;劣势:Compaction 会占用 IO 和 CPU。

列存扩展路线(TimescaleDB、金仓 KES 时序模块):

bash 复制代码
Hypertable(超表) → 按时间分区 Chunk → 列式压缩存储

优势:SQL 兼容性好,支持复杂 JOIN;劣势:压缩和分区需要手动调优。

自定义引擎路线(Prometheus、IoTDB):

bash 复制代码
自定义文件格式 → 时序索引 + 列压缩 → 针对性优化

优势:针对时序场景极致优化;劣势:通用性弱,生态工具有限。

1.3 基数(Cardinality)------选型的关键指标

"基数"指不同时间序列的总数。计算公式:

bash 复制代码
基数 = 设备数 × 指标数 × 标签组合数

例如:100 个设备,每个设备 5 个指标,每个指标有 3 个标签维度(产线、区域、类型),基数 = 100 × 5 × 3 = 1500。

基数对性能的影响是指数级的:

  • 每个序列需要维护独立的元数据(内存开销)
  • 高基数会导致倒排索引膨胀
  • InfluxDB OSS 在 series 超过百万时会显著降速

实战建议:选型前必须评估未来 1-2 年的基数增长,别只看当前数据量。


二、主流时序数据库技术对比

2.1 架构对比

维度 InfluxDB TimescaleDB TDengine Prometheus IoTDB
存储引擎 TSM(Columnar+LSM) PostgreSQL 扩展 自研列存 TSDB(本地磁盘) 自研列存
查询语言 Flux/InfluxQL SQL SQL(类) PromQL SQL/REST
SQL兼容 有限 完全(继承PG) 部分 无 部分
分布式 企业版支持 原生支持(原生分片) 原生支持 无(单节点) 原生支持
基数限制 OSS 有限制 受PG限制 高 百万级 千万级
开源协议 MIT PostgreSQL AGPL Apache Apache

2.2 性能基准参考

以下是综合社区实测和厂商文档的数量级参考(具体数据因硬件、配置差异会有波动):

写入吞吐(单节点):

  • InfluxDB 2.x:约 50-100 万 points/s
  • TimescaleDB:约 30-80 万 rows/s(依赖 COPY 批量写入)
  • TDengine:约 100-200 万 rows/s(单表模型优势)
  • 金仓 KES 时序模块:约 80-150 万 rows/s(批量写入)

压缩比:

  • InfluxDB TSM:通常 10:1 ~ 20:1
  • TimescaleDB 列压缩:约 5:1 ~ 15:1
  • TDengine:约 10:1 ~ 30:1(单表模型 + 列存)
  • Prometheus:约 3:1 ~ 5:1

注意:以上数据来自社区实测和产品文档,不同硬件、数据特征和配置下差异很大。建议在自己的场景下做 POC 测试,别直接拿别人的数据做决策。

2.3 各自的适用边界

InfluxDB:适合中小规模监控场景,社区生态最丰富,Grafana/Telegraf 无缝对接。但如果基数过高或需要分布式,需要上企业版。

TimescaleDB:适合已有 PostgreSQL 生态的团队。SQL 完全兼容,可以做复杂 JOIN 和分析查询。但需要手动调优 hypertable 配置,不如纯时序库开箱即用。

TDengine:适合物联网场景,单表模型(一个设备一张表)对设备数量明确的场景很友好。但 SQL 方言需要适配,且 AGPL 协议在商业化使用时需要注意。

Prometheus:云原生监控的事实标准。但它的定位是监控而非通用时序数据库,数据保留通常不超过 30 天,不适合长期数据存储。

IoTDB:适合工业互联网全链路场景,端边云一体化设计。但社区工具链丰富度不如前几位。


三、时序数据库实战:SQL 与架构

3.1 建表与数据模型

以一个工业传感器场景为例:

bash 复制代码
-- 创建时序表(类 SQL 语法)
CREATE TABLE sensor_data (
    ts        TIMESTAMP,
    device_id VARCHAR(32),
    metric    VARCHAR(16),
    value     DOUBLE,
    quality   INT
) PARTITION BY HASH(device_id) PARTITIONS 16;

-- 设置保留策略
ALTER TABLE sensor_data SET RETENTION INTERVAL '30 days';

-- 设置降采样
ALTER TABLE sensor_data SET DOWNSAMPLE '5m' 
    AGGREGATE AVG(value), MAX(value), MIN(value);

3.2 高吞吐写入

bash 复制代码
-- 批量插入(推荐)
INSERT INTO sensor_data (ts, device_id, metric, value, quality) VALUES
    ('2026-10-26 10:00:00', 'DEV001', 'temp', 42.5, 1),
    ('2026-10-26 10:00:00', 'DEV001', 'pressure', 3.2, 1),
    ('2026-10-26 10:00:01', 'DEV002', 'temp', 43.1, 1),
    -- ... 每批 1000-10000 条
;

批量插入的关键点:

  • 批次大小:1000-10000 条/批,太小吞吐低,太大内存压力大
  • 按时间排序:同一批次的数据按时间戳排序写入,压缩率更高
  • 避免单条 INSERT:每条都走一次事务日志,性能差几个数量级

3.3 典型查询模式

bash 复制代码
-- 最近 1 小时平均值(5 分钟窗口)
SELECT 
    time_bucket('5m', ts) AS bucket,
    device_id,
    AVG(value) AS avg_val,
    MAX(value) AS max_val
FROM sensor_data
WHERE ts >= NOW() - INTERVAL '1 hour'
  AND metric = 'temp'
GROUP BY bucket, device_id
ORDER BY bucket DESC;

-- 异常检测(偏离平均值 2 个标准差)
SELECT ts, device_id, value
FROM sensor_data
WHERE metric = 'temp'
  AND ts >= NOW() - INTERVAL '24 hours'
  AND ABS(value - (
      SELECT AVG(value) FROM sensor_data 
      WHERE metric = 'temp' 
      AND ts >= NOW() - INTERVAL '24 hours'
  )) > 2 * (
      SELECT STDDEV(value) FROM sensor_data 
      WHERE metric = 'temp' 
      AND ts >= NOW() - INTERVAL '24 hours'
  );

-- 多设备对比
SELECT 
    time_bucket('1h', ts) AS bucket,
    device_id,
    AVG(value) AS avg_temp
FROM sensor_data
WHERE metric = 'temp'
  AND ts >= NOW() - INTERVAL '7 days'
  AND device_id IN ('DEV001', 'DEV002', 'DEV003')
GROUP BY bucket, device_id
ORDER BY bucket, device_id;

四、跨模关联查询------一个被忽视的需求

很多时序数据库的文档只讲"如何存和查时序数据",但实际业务往往不是这样的。

还是那个工厂的场景:

  • 传感器数据是时序的(温度、压力)
  • 设备台账是关系型的(设备编号、型号、采购日期、维保记录)
  • 工单系统是文档型的(维修报告、检测记录)

当你要回答"哪些采购超过 3 年的设备,最近 7 天温度异常次数最多"时,就需要时序数据和关系型数据的 JOIN。

如果时序数据和设备台账在不同的数据库里,你要么:

  1. 在应用层做两次查询然后拼接(效率低、代码复杂)
  2. 搞 ETL 把数据同步到一起(延迟、维护成本)
  3. 接受数据不一致

这也是我在看选型方案时比较关注的一点。金仓 KES 的多模能力在这个场景下有个天然优势:它在同一个数据库内核里同时支持关系型、时序、文档三种数据模型。

设备台账存关系表、传感器数据走时序模块、工单存文档,都在同一个数据库实例里。要做跨模 JOIN 直接写 SQL,不用跨库同步,不用搞 ETL。

而且因为是同一个内核,事务一致性、高可用和备份恢复是一套体系,不用给时序模块单独搭 HA。

我的判断

如果你的业务只有纯时序数据采集,选 InfluxDB/TimescaleDB/TDengine 都行。但如果你的数据格局是"时序 + 关系 + 文档"混合,且需要做跨模关联,多模一体方案能省去大量运维成本。选型不是比谁的单点指标更强,而是看谁更匹配你的整体数据架构。


五、从 MySQL 到时序数据库的迁移路径

5.1 迁移评估

先看三个关键数据:

  • 现有表大小(行数 + 存储占用)
  • 写入 QPS(每秒写入次数)
  • 查询类型分布(按时间范围?按设备分组?聚合类型?)

5.2 双写方案

bash 复制代码
应用层写入流程改造:

原始:App → MySQL
改造:App → MySQL(保留)
          → 新时序库(验证)

并行运行 1-2 周,对比:
- 写入延迟(P99)
- 查询响应时间
- 数据一致性(抽样对比)

5.3 历史数据迁移

bash 复制代码
# 1. 从 MySQL 导出(按时间范围分批)
mysqldump -u root -p sensor_db sensor_data \
    --where="ts >= '2026-01-01' AND ts < '2026-04-01'" \
    > sensor_data_q1.sql

# 2. 导入新时序库
# 根据目标库的导入工具执行

# 3. 数据校验
# 对比源库和目标库的行数、聚合值

5.4 切换与回退

  1. 读请求先切到新库(写仍然双写)
  2. 观察 1-2 周,确认查询性能和数据正确
  3. 关闭 MySQL 写入
  4. 保留 MySQL 数据 30 天作为回退保障

六、避坑指南:时序数据库常见的 4 个坑

坑 1:基数失控

这是最致命的坑。基数 = 设备数 × 指标数 × 标签维度组合数。

避免方法:

  • 控制标签维度数量(尽量不超过 3-4 个)
  • 避免使用高基数字段做标签(如用户 ID、时间戳本身)
  • 定期评估基数增长趋势

坑 2:不做容量规划

时序数据是持续增长的,不做规划迟早被打满。

规划公式:

bash 复制代码
年数据量 = 设备数 × 指标数 × 采集频率 × 8760小时 × 3600秒
存储占用 = 年数据量 × 单行大小 × (1 / 压缩比)

坑 3:忽略压缩配置

不同数据的压缩效果差异很大:

  • 单调递增数据(计数器)压缩率最高
  • 波动数据(温度、压力)压缩率中等
  • 随机数据(哈希值)几乎不可压缩

建议:测试阶段就要用真实数据做压缩比测试,别用合成数据。

坑 4:不考虑关联查询需求

选型时只考虑"存和查时序数据",忽略了"以后要跟其他数据关联"。

建议:评估未来 1-2 年的数据格局变化,是否需要与关系型数据 JOIN,是否需要文档存储。


七、总结

选型时序数据库,核心看这四件事:

架构匹配:LSM-Tree 适合高写入,列存扩展适合复杂查询,自定义引擎适合极致性能。没有银弹,只有取舍。

基数可控:评估当前基数和未来增长,选的产品在你目标基数范围内性能不衰减。

运维成本:一套时序库 + 一套关系库 + ETL,vs 一个多模数据库。长期来看,后者运维成本更低。

留好空间:数据底座要能生长。今天的纯时序需求,明天可能变成跨模关联需求。选型时给未来留余地。

小耶在手,SQL 不愁

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽......我们下次见~

相关推荐
泡海椒2 小时前
深度解析JQuick-SQL AST到逻辑计划转换机制|分布式SQL原理
数据库·分布式·sql
心静财富之门2 小时前
Python 数据共享四种方案完整实例(同进程 / JSON / Redis / HTTP)
数据库·python·oracle
略略略咯咯2 小时前
啊啊啊啊啊
java·服务器·数据库
wu_solo2 小时前
6.1 Transformer架构概述
深度学习·架构·transformer
张一凡932 小时前
把“不要乱改”从提示词里拿出来,放进可校验的提案里
前端·后端·架构
奇牙coding2 小时前
GPT-5.5 报 401 invalid_api_key 怎么办?换密钥前按 4 层排查请求头、项目权限和端点
数据库·gpt·ios·ai
IvorySQL2 小时前
PostgreSQL 日报| WAL summarizer 断言失败(10 月 26 日)
数据库·postgresql·区块链
王仔小奶3 小时前
慢SQL治理与性能调优:DBA如何用Shell/Python提升运维效率?
python·sql·dba
合尘猫3 小时前
词元涨价近一倍后,我把 AI 客服的成本拆成了四个可优化的变量
人工智能·后端·架构