首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >时序数据库入门实战:从概念到第一个查询(附完整 SQL 示例)

时序数据库入门实战:从概念到第一个查询(附完整 SQL 示例)

原创
作者头像
李白客
发布2026-09-09 15:59:01
发布2026-09-09 15:59:01
780
举报

海量带时间戳的数据(传感器、监控指标、行情快照)用关系型数据库存储,迟早会撞上三堵墙:写入顶不住、存储膨胀、时间范围查询越来越慢。 这篇文章用一个最小可运行的示例,带你走完"理解时序数据 → 数据建模 → 建表 → 写入 → 查询 → 聚合 → 连续聚合 → 压缩 → 保留策略"的完整链路,看完就能照着上手。


一、先认清时序数据长什么样

1. 一条时序数据的四要素

一条时序数据由四个要素构成,这是理解一切机制的地基:

概念

说明

示例

timestamp

时间戳,数据发生的时间

2026-09-09 10:00:00

metric

指标名,量的是什么

temperature

tag

标签/维度,用来"筛"数据

device_id=01region=beijing

field

数值,用来"算"数据

75.5

记住一条建模原则:tag 用来筛选,field 用来计算。 所有"按什么分组、按什么过滤"的维度都放进 tag,所有"求和、取均值、取最大"的量都放进 field。这一条搞反了,后面的查询和压缩都会很难受。

2. 时序数据的三个特征

  • 只追加不改:数据按时间往里写,几乎不更新不删除。
  • 时间戳天然有序:查询永远是"最近一小时""过去七天"这类时间范围。
  • 指标基数高:一台设备一个 ID,几万台设备就是几万个 tag 组合。

3. 建模最佳实践(竞品文章很少讲,但最容易踩坑)

  • 时间分桶:把连续时间切成固定窗口(1 分钟、1 小时),聚合查询统一按桶走。
  • 避免高基数(Cardinality Explosion):tag 的组合数别失控。比如把"设备 ID + 用户 ID + 会话 ID"全塞进 tag,组合数会指数爆炸,拖垮索引和内存。tag 只放真正需要分组过滤的维度。
  • 单值优先:一个 field 只存一个数值,别把"温度、湿度、电压"打包成一个 JSON 字段,否则没法分别聚合、也没法压缩。

二、为什么关系库扛不住

关系型数据库不是"不行",是它没为时序数据做任何优化,三个硬伤:

  1. 写入吞吐顶不住:关系库每条记录都要维护索引、日志、约束、事务,单机每秒几万条就是天花板;工业 IoT 场景动辄每秒几十万到上百万点,直接写崩。
  2. 存储膨胀:关系库按"行"存储,一条时序数据只有"时间戳 + 设备ID + 一个数值"三个字段,却要带上一整行索引和元数据开销,表空间像吹气球。
  3. 时间范围查询慢:"查过去 7 天平均温度"是典型的时间范围扫表,关系库没有按时间分区的意识,只能全表扫。

时序库围绕"时间"做了三件事来对症下药:按时间自动分片、列式存储、时序专用压缩。下面先讲原理,再上代码。


三、时序库的三个底层机制

1. 超表自动分片(Hypertable / Chunk)

一张逻辑时序表,按时间窗口自动拆成多个物理子表(chunk)。写入只碰当前活跃 chunk,避免全局锁竞争;查询按时间条件精准定位 chunk,扫描量小几个数量级。这是时序库"写得进、查得快"的核心来源。

2. 列式存储 + 时序专用压缩

时序数据是数值型、按时间有序、相邻值高度相似,非常适合列式存储和专用压缩算法——Delta-of-Delta 差分编码(只存相邻时间戳的差值)和 Gorilla 浮点压缩(利用浮点数的位级规律)。典型数字型时序数据压缩比可达 10:1,存储降到原来的十分之一。

3. 连续聚合

监控场景里你要看的是"每小时 CPU 均值",而不是一亿条原始点。连续聚合就是提前按分钟/小时/天把聚合结果算好存进物化视图,查询直接读结果,用存储换查询速度。这一节后面有完整 SQL。


四、上手实战:完整 SQL 链路

以最易上手的 TimescaleDB(PostgreSQL 扩展)为例,思路对所有时序库通用。

1. 建表 + 转成超表

代码语言:sql
复制
-- 建时序表
CREATE TABLE conditions (
  time        TIMESTAMPTZ NOT NULL,
  device_id   TEXT,
  temperature DOUBLE PRECISION,
  humidity    DOUBLE PRECISION
);

-- 转成超表,按时间维度自动分区
SELECT create_hypertable('conditions', 'time');

2. 写入数据

代码语言:sql
复制
INSERT INTO conditions (time, device_id, temperature, humidity) VALUES
  (now(), 'device_01', 75.5, 61.0),
  (now(), 'device_02', 74.8, 62.0);

大批量写入时用批插(batch insert)或专用写入协议,能把吞吐提一个数量级。

3. 时间范围查询

代码语言:sql
复制
-- 最近 24 小时的数据
SELECT * FROM conditions
WHERE time > now() - interval '24 hours'
ORDER BY time DESC;

4. 降采样 + 时间桶聚合

代码语言:sql
复制
-- 过去 7 天,按 5 分钟一桶做聚合(降采样)
SELECT time_bucket('5 minutes', time) AS bucket,
       device_id,
       avg(temperature) AS avg_temp,
       max(temperature) AS max_temp,
       min(temperature) AS min_temp
FROM conditions
WHERE time > now() - interval '7 days'
GROUP BY bucket, device_id
ORDER BY bucket;

time_bucket 就是"时间分桶"的落地:把一秒一条的高频数据,抽稀成五分钟一个均值/最大值/最小值。趋势还在,数据量降了 300 倍。

5. 连续聚合(物化视图预计算)

代码语言:sql
复制
-- 按小时预计算聚合结果,查询直接读它
CREATE MATERIALIZED VIEW conditions_hourly
WITH (timescaledb.continuous) AS
SELECT time_bucket('1 hour', time) AS hour,
       device_id,
       avg(temperature) AS avg_temp,
       count(*)         AS cnt
FROM conditions
GROUP BY hour, device_id;

之后查"每小时温度均值"直接读 conditions_hourly,不用现场扫原始数据,响应从秒级降到毫秒级。

6. 压缩(可选,大幅降成本)

代码语言:sql
复制
-- 开启列式压缩,按 device_id 分段、按 time 排序
ALTER TABLE conditions SET (
  timescaledb.compress,
  timescaledb.compress_segmentby = 'device_id',
  timescaledb.compress_orderby  = 'time'
);

-- 7 天前的数据自动压缩
SELECT add_compression_policy('conditions', interval '7 days');

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

代码语言:sql
复制
-- 原始数据只保留 30 天,到期自动删除
SELECT add_retention_policy('conditions', interval '30 days');

-- 也可以手动清理指定时间之前的分片
SELECT drop_chunks('conditions', older_than => interval '30 days');

不设保留策略是新手最常见的坑:时序数据"越旧越不值钱",不给它设保质期,存储会被历史数据慢慢吃光。标准做法是"原始数据存 30 天 → 降采样/连续聚合结果存一年 → 到期自动删"。


五、性能与选型参考

1. 写入 / 压缩量级参考

不同产品来自不同测试口径,横向直接比没有意义,重点看量级,最终以你自己的数据量做 POC 为准:

产品

类型

写入量级

压缩比(量级)

金仓 KES TimeSeries

融合多模(国产)

TSBS 基准 124 万+点/秒

约 10 倍

TDengine

专用时序引擎(国产)

单线程约 50 万点/秒

8~15 倍

InfluxDB

专用时序引擎

约 20 万点/秒

5~8 倍

TimescaleDB

PostgreSQL 扩展

约 15 万点/秒

3~5 倍

2. 选型速查

场景

建议

时序数据与业务数据频繁关联、走信创

金仓 KES TimeSeries(融合多模,时序+关系同库 JOIN,兼容 InfluxDB 协议)

纯 IoT / 监控采集,追性能与压缩

TDengine / InfluxDB

已有 PostgreSQL 技术栈、要复杂 SQL 分析

TimescaleDB

只搭监控看板

Prometheus


六、云上落地与冷热分层

云上使用时序数据库,除了托管运维、弹性伸缩、跨可用区高可用,最能省钱的是冷热分层存储

  • 热数据(最近几小时/几天):放高性能存储,保证查询快。
  • 冷数据(历史数据):按保留策略自动归档到对象存储(如 OSS/COS),查询按需回温。
  • 回温成本:冷数据查询有额外的加载延迟,所以归档前先把常用的降采样/聚合结果留在热层,原始明细才下沉冷层。

这个"原始明细下沉 + 聚合结果常驻"的组合,就是前面连续聚合和保留策略在云上的完整闭环。


七、避坑清单

  1. 别拿关系库硬扛时序——写入、存储、查询三头挨打。
  2. 别忘设保留策略——不设保质期,存储迟早被历史数据吃光。
  3. 别在时序库里存强关系数据——订单、用户、账户这类主外键数据,时序库帮不上忙。
  4. 别把高基数维度全塞进 tag——tag 组合爆炸会拖垮索引和内存,建模前先想清楚分组维度。
  5. 别信单一口径的性能数字——各家测试环境不同,拿自己的数据量做 POC 才是正路。

小结

时序数据库解决的就一件事:让海量带时间戳的数据存得下、写得进、查得快、还省钱。

如果你的数据"只写不改、每条带时间戳、要按时间查趋势",就别再用关系库硬扛了——换对数据库类型,往往比加机器更管用。本文的完整 SQL 链路(建表 → 写入 → 查询 → 聚合 → 连续聚合 → 压缩 → 保留策略)可以当作模板直接套用。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、先认清时序数据长什么样
    • 1. 一条时序数据的四要素
    • 2. 时序数据的三个特征
    • 3. 建模最佳实践(竞品文章很少讲,但最容易踩坑)
  • 二、为什么关系库扛不住
  • 三、时序库的三个底层机制
  • 四、上手实战:完整 SQL 链路
    • 1. 建表 + 转成超表
    • 2. 写入数据
    • 3. 时间范围查询
    • 4. 降采样 + 时间桶聚合
    • 5. 连续聚合(物化视图预计算)
    • 6. 压缩(可选,大幅降成本)
    • 7. 数据保留策略(过期自动清理)
  • 五、性能与选型参考
    • 1. 写入 / 压缩量级参考
    • 2. 选型速查
  • 六、云上落地与冷热分层
  • 七、避坑清单
  • 小结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档