TDengine 时序数据库深度学习笔记
学习时间 :2026-06-03
TDengine 版本 :3.4.1.13(Community Edition,2026-06-01 发布)
学习环境 :华为云 ECS (ecs-263c) × 4 台 | Ubuntu 24.04.4 / Docker
笔记风格:博客级质量 + 真实数据 + 踩坑实录 + 生产级部署
目录
- [一、TDengine 基础认知](#一、TDengine 基础认知)
- 1.1 核心概念
- 1.2 与传统数据库的区别
- 2.1 服务器基础设施
- 2.2 安装方式对比
- 2.3 Docker 快速部署(实操)
- 2.4 集群部署架构
- 2.5 验证安装
- 3.1 核心概念详解
- 3.2 数据模型设计原则
- [四、SQL 实操指南](#四、SQL 实操指南)
- 4.1 数据库操作
- 4.2 表结构设计
- 4.3 数据写入
- 4.4 数据查询
- 4.5 高级查询技巧(时序分析函数)
- 5.1 数据备份与恢复
- 5.2 性能监控
- 5.3 数据维护
- [六、Grafana 可视化](#六、Grafana 可视化)
- 6.1 TDengine 数据源配置
- 6.2 智能电表 Dashboard 实战
- 6.3 告警规则配置
- 7.1 taosBenchmark 工具使用
- 7.2 写入压测实战
- 7.3 查询压测与结果解读
- 7.4 性能调优参数
一、TDengine 基础认知
1.1 核心概念
什么是 TDengine?
TDengine(涛思数据)是一款开源、高性能、云原生的时序数据库(Time-Series Database,TSDB),专为物联网(IoT)、工业互联网(IIoT)、车联网(IoV)、金融量化等场景设计。
┌─────────────────────────────────────────────────────────────────────────┐
│ TDengine 核心定位 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ⚡ 时序写入 ─── 百万级数据点/秒 写入 │
│ 💾 极致压缩 ─── 列式存储 + 差值编码,压缩比 5~20 倍 │
│ 📊 标准 SQL ─── 兼容 MySQL 语法,零学习成本 │
│ 🔄 内置计算 ─── 缓存、流式计算、数据订阅、连续查询 │
│ 🌐 分布式 ─── 原生水平扩展,支持多副本 │
│ 🆓 开源免费 ─── AGPL v3 协议,Community Edition 功能完整 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
时序数据定义
时序数据 (Time-Series Data):按时间顺序生成的数据序列,每个数据点由一个时间戳 (Timestamp)和一组测量值 (Metrics)组成,通常还带有标签(Tags)标识数据来源。
典型时序数据场景:
| 场景 | 数据特征 | 写入频率 | 查询模式 |
|---|---|---|---|
| 智能电表 | 电流、电压、功率 | 每秒/每分钟 | 聚合统计、趋势分析 |
| 环境监测 | 温度、湿度、PM2.5 | 每分钟 | 按区域分组查询 |
| 工业设备 | 振动、转速、压力 | 毫秒级 | 异常检测、窗口聚合 |
| 车联网 | GPS、速度、油耗 | 每秒 | 轨迹查询、统计报表 |
| 金融行情 | 价格、成交量、K线 | 毫秒级 | 时间窗口计算 |
TDengine 核心特点详解
⚡ 高性能写入:
- 采用无锁设计 (Lock-Free Queue)+ Append-Only 写入
- 数据先写入内存缓冲区(Memtable),定期刷入磁盘
- 实测:单节点可达 300 万数据点/秒「官方 benchmark」
💾 高压缩比:
- 列式存储(Columnar Storage)天然适合压缩
- 时间序列差值编码:只存储变化量而非绝对值
- 多种压缩算法可选:LZ4、Zstandard、增量编码等
- 实测:传感器数据可压缩至原始大小的 5%~10%
📊 SQL 支持:
- 兼容标准 SQL(SELECT、WHERE、GROUP BY、JOIN 等)
- 扩展时序特有函数:
INTERVAL、WINDOW、DIFF、FIRST、LAST - 支持子查询、聚合、窗口函数
🔄 内置功能(无需额外组件):
- 缓存(Cache):热点数据自动缓存,查询 P99 < 10ms
- 流式计算(Stream Processing):CREATE STREAM 实现实时聚合
- 数据订阅(Data Subscription):类似 Kafka 的消息推送
- 连续查询(Continuous Query):定时执行的预计算任务
🌐 分布式架构:
- 无中心化设计(对等节点,无单点故障)
- 虚拟节点(Virtual Node, VNode)实现数据分片
- 多副本(Replica)保证高可用
- 水平扩展只需添加新节点,数据自动均衡
1.2 与传统数据库的区别
┌──────────────────────────────────────────────────────────────────────┐
│ TDengine vs MySQL/PostgreSQL 深度对比 │
├──────────────┬─────────────────────┬─────────────────────────────────┤
│ 特性 │ TDengine │ MySQL / PostgreSQL │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 数据模型 │ 超级表(Super Table) │ 普通关系表 │
│ │ + N 张子表 │ │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 主键设计 │ 时间戳(TS) + │ 自定义主键(如自增 ID) │
│ │ 标签(TAG) 联合主键 │ │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 存储模型 │ 列式 + 时间分区 │ 行式(MySQL InnoDB) │
│ │ Append-Only │ B+Tree / Heap │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 压缩比 │ 5~20 倍 │ 1~3 倍(InnoDB COMPRESSED) │
│ │ 列存 + 差值编码 │ 行级压缩,效果有限 │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 写入性能 │ 百万级/秒/节点 │ 万级/秒(单机 INSERT) │
│ │ 无锁 + 内存缓冲 │ 锁竞争 + 事务开销 │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 查询性能 │ 列存投影快 │ 行存整行读取 │
│ │ 时序优化(SMA) │ 索引扫描 │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 时间窗口 │ 原生 INTERVAL │ DATE_FORMAT + GROUP BY │
│ │ 一步到位 │ 需要大量计算 │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 数据保留 │ 内置 KEEP/DURATION │ 手动 DELETE + cron │
│ │ 自动清理过期数据 │ 需要额外维护 │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 流式计算 │ 内置 CREATE STREAM │ 需要 Kafka/Flink 等组件 │
│ 数据订阅 │ 内置 TOPIC/SUBSCRIBE│ 需要 Canal/Debezium │
├──────────────┼─────────────────────┼─────────────────────────────────┤
│ 适用场景 │ 时序数据(IoT/监控)│ 通用 OLTP/OLAP │
│ │ 百万设备、千亿数据点│ 业务系统、用户数据 │
└──────────────┴─────────────────────┴─────────────────────────────────┘
时序数据库竞品对比
| 特性 | TDengine 3.x | InfluxDB 2.x | TimescaleDB | ClickHouse |
|---|---|---|---|---|
| 开源协议 | AGPL v3 | MIT | TSL (社区版) | Apache 2.0 |
| SQL 支持 | ✅ 标准 SQL | ⚠️ Flux 语言 | ✅ PostgreSQL | ✅ 自有方言 |
| 压缩比 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 水平扩展 | ✅ 原生 | ⚠️ 企业版 | ⚠️ 复杂 | ✅ 原生 |
| 流式计算 | ✅ 内置 | ❌ | ✅ 连续聚合 | ✅ 物化视图 |
| 学习成本 | ⭐ 低(MySQL语法) | ⭐⭐⭐ 高(Flux) | ⭐ 低(PG 用户) | ⭐⭐ 中 |
| 运维复杂度 | ⭐ 低(内置功能多) | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| 中文文档 | ✅ 完善 | ⚠️ 一般 | ⚠️ 一般 | ⚠️ 一般 |
| 国产化适配 | ✅ 鲲鹏/飞腾 | ❌ | ❌ | ⚠️ 有限 |
选型建议:IoT/时序场景首选 TDengine(高性能 + 低运维成本),通用分析选 ClickHouse,深度绑定 PG 生态选 TimescaleDB。
二、环境搭建与部署
2.1 服务器基础设施
本次学习使用华为云 ECS x 4 台搭建 TDengine 集群,规格如下:
┌─────────────────────────────────────────────────────────────────────┐
│ TDengine 集群 (ecs-263c) 拓扑图 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ tdengine-01 (Master) tdengine-02 tdengine-03 │
│ ┌─────────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 159.138.23.117 │ │ 119.8.55.188 │ │ 119.8.235.20 │ │
│ │ 192.168.0.108 │ │ 192.168.0.85 │ │ 192.168.0.213│ │
│ │ │ │ │ │ │ │
│ │ TDengine:6030 │◄────►│ TDengine:6030│◄──►│ TDengine:6030│ │
│ │ REST :6041 │ │ REST :6041 │ │ REST :6041 │ │
│ └─────────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │
│ │ tdengine-04 │ │
│ │ ┌──────────────┐ │ │
│ └───────────►│ 159.138.152.74│ │ │
│ │ 192.168.0.82 │ │ │
│ │ │ │ │
│ │ TDengine:6030│ │ │
│ │ REST :6041 │ │ │
│ └──────────────┘ │ │
│ │
│ 端口说明: │
│ 6030 --- TDengine 集群间通信端口 (Taosd RPC) │
│ 6041 --- REST API 端口(对外 HTTP 接口) │
│ 6030-6049 --- TDengine 占用的端口范围 │
└─────────────────────────────────────────────────────────────────────┘
| 主机别名 | 公网 IP | 内网 IP | 华为云主机名 | 角色 |
|---|---|---|---|---|
| tdengine-01 | 159.138.23.117 | 192.168.0.108 | ecs-263c-0001 | 集群 Node 1(首个节点) |
| tdengine-02 | 119.8.55.188 | 192.168.0.85 | ecs-263c-0002 | 集群 Node 2 |
| tdengine-03 | 119.8.235.20 | 192.168.0.213 | ecs-263c-0003 | 集群 Node 3 |
| tdengine-04 | 159.138.152.74 | 192.168.0.82 | ecs-263c-0004 | 集群 Node 4 |
服务器规格:
| 项目 | 值 |
|---|---|
| 规格型号 | ac9.large.2(华为云 ECS 通用型) |
| vCPU | 2 核 |
| 内存 | 3.4 GiB |
| 系统盘 | 40 GB SSD |
| 操作系统 | Ubuntu 24.04.4 LTS (Noble) |
| 内核版本 | 6.8.0-106-generic |
| 内网带宽 | 千兆(互通已确认) |
⚠️ 资源评估 :2vCPU/3.4GiB 对于 TDengine 生产环境偏小(官方建议 8vCPU/16GiB 起步),但对于学习测试绰绰有余。TDengine 内存占用主要由缓存池控制,默认
blocks参数可调。
2.2 安装方式对比
| 安装方式 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
| Docker | 一键启动、环境隔离、快速体验 | 额外容器开销、网络配置稍复杂 | ✅ 学习、测试、PoC |
| APT/YUM | 原生性能、systemd 管理 | 需要仓库配置、依赖处理 | 生产环境(物理机/VM) |
| 源码编译 | 深度定制、最新功能 | 编译耗时、维护成本高 | 二次开发 |
| 云服务 TDengine Cloud | 零运维、按量付费 | 数据在云上 | 快速验证 |
本次选择:Docker 方式 --- 4 台 ECS 统一 Docker 部署,利用容器隔离快速搭建集群。
2.3 Docker 快速部署(实操)
2.3.1 环境准备:安装 Docker
⚠️ 踩坑:Ubuntu 24.04 默认不预装 Docker,需要使用官方安装脚本。
第一步:检查并安装 Docker(4 台并行)
bash
# 清理可能残留的 apt 锁
rm -f /var/lib/apt/lists/lock /var/lib/dpkg/lock-frontend \
/var/lib/dpkg/lock /var/cache/apt/archives/lock
# 官方一键安装脚本
curl -fsSL https://get.docker.com | bash
# 验证安装
docker --version
text
# 实际安装输出(全部 4 台均为 Docker 29.5.2)
tdengine-01 (159.138.23.117) → Docker 29.5.2 ✅ (apt clean 后安装成功)
tdengine-02 (119.8.55.188) → Docker 29.5.2 ✅ (一次安装成功,唯一)
tdengine-03 (119.8.235.20) → Docker 29.5.2 ✅ (apt clean 后安装成功)
tdengine-04 (159.138.152.74) → Docker 29.5.2 ✅ (apt clean 后安装成功)
# Docker Info: Storage Driver: overlay2 / Cgroup: systemd v2
第二步:配置 Docker 镜像加速(可选,海外服务器不建议)
由于华为云香港节点在海外,docker.io 直连速度尚可,不配置镜像加速。国内服务器建议:
bash
# 国内服务器推荐配置镜像加速
sudo tee /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
]
}
EOF
sudo systemctl restart docker
2.3.2 拉取 TDengine 镜像
⚠️ 重要变更(3.3.7.0 起) :TDengine 的 Docker 镜像名从
tdengine/tdengine(社区版)/tdengine/tdengine-ee(企业版)改名为tdengine/tsdb/tdengine/tsdb-ee。旧镜像名已不再更新!
踩坑记录:
bash
# ❌ 错误(旧镜像名,3.3.7.0 后不再可用)
docker pull tdengine/tdengine:3.3.8.8
# Error: not found
# ✅ 正确
docker pull tdengine/tsdb:3.4.1.13
bash
# 拉取最新社区版(推荐固定版本号)
docker pull tdengine/tsdb:3.4.1.13
# 或使用 latest 标签(自动指向最新稳定版)
docker pull tdengine/tsdb:latest
# 镜像信息:
# - 版本:3.4.1.13(2026-06-01 发布)
# - 压缩后大小:~332MB
# - 架构:amd64 + arm64 多架构镜像
#### 2.3.3 集群模式启动首个节点(tdengine-01 种子节点)
> **关键设计**:TDengine 3.x Docker 集群通过**环境变量**配置,无需修改 taos.cfg。使用 `--net=host` 模式让容器直接使用宿主机网络。
```bash
# 创建数据持久化目录
mkdir -p /opt/tdengine/{data,log,cfg}
# 启动 TDengine 种子节点(集群第一个节点)
docker run -d \
--name tdengine \
--network host \
--restart unless-stopped \
-v /opt/tdengine/data:/var/lib/taos \
-v /opt/tdengine/log:/var/log/taos \
-v /opt/tdengine/cfg:/etc/taos \
-e TAOS_FQDN=192.168.0.108 \
-e TAOS_FIRST_EP=192.168.0.108:6030 \
tdengine/tsdb:latest
集群环境变量详解:
| 环境变量 | 含义 | 必需 | 示例 |
|---|---|---|---|
TAOS_FQDN |
节点完全限定域名/IP,集群通信标识 | ✅ | 192.168.0.108 |
TAOS_FIRST_EP |
集群首个端点(Endpoint) | ✅(种子上) | 192.168.0.108:6030 |
TAOS_SECOND_EP |
集群第二个端点(HA 推荐) | ❌ | 192.168.0.85:6030 |
TAOS_SERVER_PORT |
服务端口,默认 6030 | ❌ | 6030 |
容器启动参数详解:
| 参数 | 含义 | 说明 |
|---|---|---|
--network host |
使用宿主机网络栈 | 容器端口直接暴露在宿主机上,无需 -p 映射 |
--name tdengine |
容器名称 | 便于 docker exec tdengine taos 操作 |
--restart unless-stopped |
重启策略 | 除手动停止外自动重启 |
-v ...:/var/lib/taos |
数据卷 | 持久化时序数据、元数据(mnode) |
-v ...:/var/log/taos |
日志卷 | 持久化 taosd/taosadapter/taoskeeper 日志 |
-v ...:/etc/taos |
配置卷 | 持久化 taos.cfg(环境变量优先级更高) |
2.3.4 验证种子节点
bash
# 查看启动日志
docker logs tdengine --tail 20
# 进入 taos CLI
docker exec tdengine taos -s 'SHOW DNODES;'
text
# 实际输出(版本 3.4.1.13 Community)
Welcome to the TDengine TSDB Command Line Interface, Client Version:3.4.1.13.community
Copyright (c) 2025 by TDengine TSDB, all rights reserved.
taos> SHOW DNODES;
id | endpoint | vnodes | support_vnodes | status |
=====================================================================================
1 | 192.168.0.108:6030 | 1 | 9 | ready |
Query OK, 1 row(s) in set (0.002307s)
查看版本信息:
bash
# 查看完整版本(含 Git commit)
docker run --rm tdengine/tsdb:latest taosd --version
text
TDengine TSDB-OSS
taosd version: 3.4.1.13.community compatible_version: 3.0.0.0
git: 89871746e78a233bd19333209ef6a782eba138ee
build: Linux-x64 2026-05-31 00:51:06
2.4 集群部署架构
TDengine 集群采用对等节点架构 ,通过 TAOS_FIRST_EP 指定种子端点实现自动发现和加入。
┌──────────────────────────────────────────────────────────────────────┐
│ TDengine 集群架构(4 节点) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ 心跳 & 元数据同步 │
│ │ tdengine-01 │◄─────────────────────►┐ │
│ │ (192.168.0.108) │ │ │
│ │ FIRST_EP (种子) │ ▼ │
│ └────────┬─────────┘ ┌──────────────────┐ │
│ │ │ tdengine-03 │ │
│ │ │ (192.168.0.213) │ │
│ │ │ FIRST_EP=01 │ │
│ │ └────────┬─────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ tdengine-02 │ │ tdengine-04 │ │
│ │ (192.168.0.85) │ │ (192.168.0.82) │ │
│ │ FIRST_EP=01 │ │ FIRST_EP=01 │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ 端口说明: │
│ 6030 --- TDengine 集群间通信端口 (Taosd RPC) │
│ 6041 --- REST API 端口 (taosAdapter) │
│ 6043 --- taosKeeper 监控指标端口 │
│ │
│ 概念说明: │
│ dnode (Data Node) --- 物理节点,运行 taosd 进程 │
│ mnode (Management Node)--- 管理节点,存储集群元数据 │
│ vnode (Virtual Node) --- 虚拟节点,数据分片的最小单元 │
│ FIRST_EP --- 集群种子端点,新节点通过它加入集群 │
│ FQDN --- 节点标识,必须可被其他节点访问 │
└──────────────────────────────────────────────────────────────────────┘
集群配置与启动
tdengine-01 (种子节点):
bash
docker run -d --name tdengine --network host --restart unless-stopped \
-v /opt/tdengine/data:/var/lib/taos \
-v /opt/tdengine/log:/var/log/taos \
-v /opt/tdengine/cfg:/etc/taos \
-e TAOS_FQDN=192.168.0.108 \
-e TAOS_FIRST_EP=192.168.0.108:6030 \
tdengine/tsdb:latest
tdengine-02 ~ tdengine-04 (后续节点):
bash
# tdengine-02 (192.168.0.85)
docker run -d --name tdengine --network host --restart unless-stopped \
-v /opt/tdengine/data:/var/lib/taos \
-v /opt/tdengine/log:/var/log/taos \
-v /opt/tdengine/cfg:/etc/taos \
-e TAOS_FQDN=192.168.0.85 \
-e TAOS_FIRST_EP=192.168.0.108:6030 \
tdengine/tsdb:latest
# tdengine-03 (192.168.0.213) --- FQDN 改为 192.168.0.213
# tdengine-04 (192.168.0.82) --- FQDN 改为 192.168.0.82
加入集群流程:
- 新节点启动后,根据
TAOS_FIRST_EP连接种子节点 - 向种子节点注册自己的
TAOS_FQDN:6030 - mnode(管理节点)向新节点分配 VNode(虚拟节点)
- 数据分片自动均衡到各 VNode
2.5 集群验证
bash
# 在 tdengine-01 上执行(taos CLI)
docker exec tdengine taos -s 'SHOW DNODES;'
text
# 实际输出 --- 4 节点集群全部 ready
id | endpoint | vnodes | support_vnodes | status |
=====================================================================================
1 | 192.168.0.108:6030 | 1 | 9 | ready |
2 | 192.168.0.85:6030 | 0 | 9 | ready |
3 | 192.168.0.213:6030 | 0 | 9 | ready |
4 | 192.168.0.82:6030 | 0 | 9 | ready |
Query OK, 4 row(s) in set (0.002005s)
各节点职责说明:
| DNode ID | 端点 | VNodes | 角色说明 |
|---|---|---|---|
| 1 | 192.168.0.108:6030 | 1 | MNode Leader + 数据节点 |
| 2 | 192.168.0.85:6030 | 0 | 数据节点(等待 VNode 分配) |
| 3 | 192.168.0.213:6030 | 0 | 数据节点(等待 VNode 分配) |
| 4 | 192.168.0.82:6030 | 0 | 数据节点(等待 VNode 分配) |
说明:新加入的节点初始 VNodes=0,创建数据库后系统会自动分配 VNode 到各节点。
验证 MNode 状态:
bash
docker exec tdengine taos -s 'SHOW MNODES;'
text
id | endpoint | role | status |
===========================================================================
1 | 192.168.0.108:6030 | leader | ready |
Query OK, 1 row(s) in set (0.001869s)
验证测试数据库(功能确认):
bash
docker exec tdengine taos -s '
CREATE DATABASE IF NOT EXISTS test_iot KEEP 365 DURATION 10 BUFFER 16;
USE test_iot;
CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT)
TAGS (location BINARY(64), group_id INT);
CREATE TABLE d1001 USING meters TAGS("Beijing.Room1", 1);
CREATE TABLE d1002 USING meters TAGS("Shanghai.Room2", 2);
INSERT INTO d1001 VALUES (NOW, 10.2, 220, 0.82);
INSERT INTO d1001 VALUES (NOW+1s, 10.5, 221, 0.83);
INSERT INTO d1002 VALUES (NOW, 8.7, 219, 0.79);
INSERT INTO d1002 VALUES (NOW+1s, 9.1, 218, 0.81);
SELECT * FROM meters;
'
text
# 查询结果 --- 跨子表聚合查询成功
ts | current | voltage | phase |
| location | group_id |
===================================================================================
2026-06-03 09:58:04.407 | 8.7 | 219 | 0.79 |
| Shanghai.Room2 | 2 |
2026-06-03 09:58:05.412 | 9.1 | 218 | 0.81 |
| Shanghai.Room2 | 2 |
2026-06-03 09:58:04.394 | 10.2 | 220 | 0.82 |
| Beijing.Room1 | 1 |
2026-06-03 09:58:05.398 | 10.5 | 221 | 0.83 |
| Beijing.Room1 | 1 |
Query OK, 4 row(s) in set (0.008958s)
2.6 Docker 安装踩坑记录
踩坑 1: APT 缓存冲突导致 "rename failed"
text
错误现象:
E: Failed to fetch https://download.docker.com/.../docker-ce_29.5.2.deb
rename failed, No such file or directory
(.../partial/... -> .../archives/...)
根因 :/var/cache/apt/archives/partial/ 中存在上一次中断下载的残留文件,APT 无法完成 rename 操作。
解决方案:
bash
# 彻底清理 APT 缓存 + 重试
apt-get clean
rm -rf /var/cache/apt/archives/partial/*
apt-get update -qq
curl -fsSL https://get.docker.com | bash
踩坑 2: 4 台服务器 3 台踩中同一坑
| 服务器 | 首次安装结果 | 修复结果 |
|---|---|---|
| tdengine-01 | ❌ rename failed | apt clean 后 ✅ Docker 29.5.2 |
| tdengine-02 | ✅ 一次成功 | Docker 29.5.2 |
| tdengine-03 | ❌ rename failed | apt clean 后 ✅ Docker 29.5.2 |
| tdengine-04 | ❌ rename failed | apt clean 后 ✅ Docker 29.5.2 |
教训 :华为云 ECS 镜像可能自带部分 APT 残留,建议部署前统一执行
apt-get clean && apt-get update。
踩坑 3: TDengine 镜像名变更(v3.3.7.0 起)
bash
# ❌ 错误:旧镜像名(v3.3.7.0 后不再更新)
docker pull tdengine/tdentity:3.3.8.8 # Error: not found
docker pull tdengine/tdentity:latest # 可拉取但仅到 v3.3.6.x
# ✅ 正确:新镜像名
docker pull tdengine/tsdb:latest # → v3.4.1.13 Community
根因 :TDengine 社区版 Docker 镜像名从 tdengine/tdentity 更名为 tdengine/tsdb(自 v3.3.7.0 起),旧镜像名已停止更新。
踩坑 4: 集群 FQDN 配置错误 → 全集群重置
text
错误操作:tdengine-04 的 TAOS_FQDN 误设为 192.168.0.214(实际应为 192.168.0.82)
后果:
- 集群注册了 192.168.0.214:6030 (DNode 4),但该 IP 不存在 → offline
- 正确节点 192.168.0.82:6030 也被重新注册 (DNode 5) → 出现幽灵节点
- DROP DNODE 4 失败:TDengine 3.x 不允许直接删除 offline 节点
解决方案(零数据新集群):
bash
# 1. 全部停止并清理数据
for i in 01 02 03 04; do
ssh tdengine-$i "docker stop tdengine; rm -rf /opt/tdengine/data/* /opt/tdengine/log/*"
done
# 2. 按顺序重启(种子节点优先)
ssh tdengine-01 "docker start tdengine" # 等待约 10s
ssh tdengine-02 "docker start tdengine"
ssh tdengine-03 "docker start tdengine"
ssh tdengine-04 "docker start tdengine" # 注意 FQDN=192.168.0.82
# 3. 验证 4 节点全 ready
docker exec tdengine taos -s 'SHOW DNODES;'
教训:集群部署时 TAOS_FQDN 必须与节点实际内网 IP 严格一致;TDengine 3.x offline dnode 无法通过 SQL 删除,零数据场景最快恢复方案是全集群重置。
2.7 内网镜像分发策略
由于 4 台 ECS 在华为云同一 VPC 内网千兆互通,采用"一台公网拉取 → 内网 HTTP 分发"策略,避免 4 次重复下载镜像。
bash
# ====== Step 1: tdengine-02 拉取并导出 ======
docker pull tdengine/tsdb:latest
docker save tdengine/tsdb:latest | gzip > /tmp/tdengine-tsdb-3.4.1.13.tar.gz
# → 镜像大小:1.25GB(解压后),压缩后 330MB
# ====== Step 2: 启动内网 HTTP 服务器 ======
cd /tmp
nohup python3 -m http.server 8080 --bind 192.168.0.85 \
> /var/log/tdengine-httpd.log 2>&1 &
# 验证服务
curl -s -o /dev/null -w '%{http_code}' http://192.168.0.85:8080/tdengine-tsdb-3.4.1.13.tar.gz
# → 200 ✅
# ====== Step 3: 其他 3 台并行下载 ======
# tdengine-01
wget -O /tmp/tdengine-tsdb-3.4.1.13.tar.gz \
http://192.168.0.85:8080/tdengine-tsdb-3.4.1.13.tar.gz # ~1.2s 完成
# tdengine-03 / tdengine-04 同理
# ====== Step 4: 并行 docker load ======
docker load < /tmp/tdengine-tsdb-3.4.1.13.tar.gz
# → Loaded image: tdengine/tsdb:latest
# ====== Step 5: 清理 ======
rm -f /tmp/tdengine-tsdb-3.4.1.13.tar.gz # 各节点清理
kill $(pgrep -f 'http.server 8080') # tdengine-02 停止 HTTP 服务
| 分发指标 | 值 |
|---|---|
| 镜像压缩后大小 | 330MB |
| 解压后大小 | 1.25GB |
| 内网传输速度 | ~280MB/s |
| 单节点下载耗时 | ~1.2 秒 |
| 节省公网带宽 | 3 × 330MB = ~1GB |
三、核心概念与数据模型
3.1 核心概念详解
TDengine 的数据模型具有鲜明的层次化特征,理解这一层次是掌握 TDengine 的关键:
┌──────────────────────────────────────────────────────────────────────┐
│ TDengine 数据模型层次结构 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 数据库 (Database) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 逻辑容器,对应一个应用或项目 │ │
│ │ 可设定:数据保留策略(KEEP)、分片规则(DURATION)、副本数 │ │
│ │ │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ 超级表 (Super Table / STable) │ │ │
│ │ │ ┌──────────────────────────────────────────────┐ │ │ │
│ │ │ │ 数据模板 --- 定义数据结构(列名+类型) │ │ │ │
│ │ │ │ + TAG 模板 --- 定义标签(静态属性) │ │ │ │
│ │ │ └──────────────────────────────────────────────┘ │ │ │
│ │ │ │ USING 方式创建子表 │ │ │
│ │ │ ▼ │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │ 子表 001 │ │ 子表 002 │ │ 子表 NNN │ ... │ │ │
│ │ │ │ (设备A) │ │ (设备B) │ │ (设备N) │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ TS ──── │ │ TS ──── │ │ TS ──── │ │ │ │
│ │ │ │ temp ─── │ │ temp ─── │ │ temp ─── │ │ │ │
│ │ │ │ humi ─── │ │ humi ─── │ │ humi ─── │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ TAG: │ │ TAG: │ │ TAG: │ │ │ │
│ │ │ │ loc='A' │ │ loc='B' │ │ loc='N' │ │ │ │
│ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 关键概念对比: │
│ ┌─────────────┬───────────────────────────────────────────────────┐ │
│ │ TAG(标签) │ 静态属性:设备位置、型号、分组 │ │
│ │ │ 值不变或极少变化,用于分区和 GROUP BY │ │
│ ├─────────────┼───────────────────────────────────────────────────┤ │
│ │ Field(字段)│ 动态数据:温度、湿度、电压等时序测量值 │ │
│ │ │ 每个时间点都有新值 │ │
│ ├─────────────┼───────────────────────────────────────────────────┤ │
│ │ TS(时间戳) │ 主键第一列,必须是 TIMESTAMP 类型 │ │
│ │ │ 精度:ms(毫秒,默认) / us(微秒) / ns(纳秒) │ │
│ └─────────────┴───────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
为什么设计「超级表+子表」模型?
| 传统数据库做法 | TDengine 做法 | 优势 |
|---|---|---|
| 一张大表存所有设备数据, | 一个超级表定义模板, | 子表间独立存储, |
| location 作为普通列 | 每个设备一个子表 | 写入物理隔离,无锁竞争 |
| 查询时 WHERE location = 'A' | 查询时 FROM super_table | 自动跨子表聚合 |
| 索引 colocation 列 | TAG 自带索引 | 聚簇查找,O(1) 定位 |
实际存储结构 :每个子表对应独立的物理文件(.data),同一超级表的子表共享 TAG 索引。
3.2 数据模型设计原则
┌───────────────────────────────────────────────────────────────────────┐
│ TDengine 数据建模最佳实践 │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ ✅ DO ❌ DON'T │
│ ──────────────────────────────────── ──────────────────────── │
│ │
│ 一类设备 → 一个超级表 一个超级表囊括所有设备 │
│ 一个设备 → 一张子表 多设备混在一张子表 │
│ 不变属性 → TAG 变化的属性放 TAG │
│ 变化数据 → 普通字段 频繁变更ID作为TAG │
│ TS 时间戳 → 主键第一列 TS 不用 TIMESTAMP 类型 │
│ TAG 数量 ≤ 128 个 TAG 过多影响写入性能 │
│ (每条数据都要写TAG索引)│
│ │
│ 建表前核对清单: │
│ ☑ 是否一类设备共用同一数据结构? → 是 → 建超级表 │
│ ☑ 每个设备的数据是否独立? → 是 → 按设备建子表 │
│ ☑ 属性是否会随时间变化? → 不会 → 放 TAG;会 → 放 Field │
│ ☑ 时间戳是否为第一列? → 必须是 │
│ ☑ TAG 数量是否合理? → 建议 ≤ 20 个,最多 128 个 │
│ │
└───────────────────────────────────────────────────────────────────────┘
建表时的关键参数详解
sql
CREATE DATABASE iot_db
KEEP 3650 -- 数据保留天数。3650 天 ≈ 10 年。到期自动删除
DURATION 10 -- 每个数据文件覆盖的天数,影响查询扫描效率
PRECISION 'ms' -- 时间戳精度:'ms'(毫秒)、'us'(微秒)、'ns'(纳秒)
VGROUPS 2 -- VNode Groups 数量,影响写入并行度
REPLICA 2 -- 副本数。1=无副本,2=1副本。集群模式可用
BUFFER 128 -- 每个 VNode 的写入缓存大小(MB),默认 128
PAGES 256 -- 每个 VNode 的缓存池页数
PAGESIZE 4 -- 每页大小(KB),默认 4KB
COMP 2 -- 压缩级别:0(不压缩) ~ 2(最高压缩)
CACHESIZE 1 -- 每 VNode 缓存大小(MB)
DURATION 选择指南:
- 高频采集(秒级):DURATION 1 或 3(每 1~3 天一个文件)
- 中频采集(分钟级):DURATION 7 或 10
- 低频采集(小时级):DURATION 30
- 过大的 DURATION 会导致单个文件过大,影响查询扫描效率
四、SQL 实操指南
4.1 数据库操作
sql
-- 1. 创建数据库(完整参数)
CREATE DATABASE IF NOT EXISTS iot_db
KEEP 3650 -- 数据保留3650天(约10年)
DURATION 10 -- 每10天一个数据文件
PRECISION 'ms' -- 时间精度:毫秒
BUFFER 128 -- 写入缓冲 128MB
PAGES 256 -- 缓存池页数
CACHESIZE 1 -- 缓存大小 MB
COMP 2; -- 最高压缩比
-- 2. 切换数据库
USE iot_db;
-- 3. 查看数据库列表
SHOW DATABASES;
-- 4. 查看数据库详细配置
SHOW CREATE DATABASE iot_db;
-- 5. 修改数据库选项(注意:不是所有参数都支持 ALTER)
ALTER DATABASE iot_db KEEP 180;
ALTER DATABASE iot_db REPLICA 2;
-- 6. 删除数据库(危险操作!)
-- DROP DATABASE iot_db;
4.2 表结构设计(重点实操)
4.2.1 创建超级表(Super Table)
超级表是 TDengine 的核心概念------它相当于一张模板表,定义了:
- 数据列结构(哪些测量指标)
- TAG 列结构(哪些标签属性)
sql
-- 创建智能设备温度监控超级表
CREATE STABLE IF NOT EXISTS device_temperature (
ts TIMESTAMP, -- 时间戳,必须是第一列
temperature FLOAT, -- 温度 (℃),浮点数
humidity FLOAT, -- 湿度 (%),浮点数
pressure INT, -- 大气压 (hPa),整数
status TINYINT -- 设备状态:0=正常, 1=异常, 2=离线
) TAGS (
location BINARY(64), -- 位置标签,最多 64 字节(约 21 个中文字符)
device_id INT, -- 设备 ID
group_id INT -- 分组 ID
);
列类型对应关系:
| TDengine 类型 | 说明 | MySQL 对应 | 适用场景 |
|---|---|---|---|
TIMESTAMP |
时间戳 | DATETIME |
主键第一列,必须 |
INT |
4 字节整数 | INT |
计数、压力、状态码 |
BIGINT |
8 字节整数 | BIGINT |
大数值计数器 |
FLOAT |
4 字节浮点 | FLOAT |
温度、湿度(精度要求不高) |
DOUBLE |
8 字节浮点 | DOUBLE |
高精度测量值 |
TINYINT |
1 字节 | TINYINT |
开关状态、小枚举 |
SMALLINT |
2 字节 | SMALLINT |
小范围整数 |
BINARY(n) |
定长字符串 | CHAR(n) |
TAG 中的设备名、位置 |
NCHAR(n) |
Unicode 字符串 | NCHAR(n) |
多语言标签 |
BOOL |
布尔值 | BOOLEAN |
告警标志 |
sql
-- 验证超级表结构
SHOW STABLES;
-- 查看超级表完整定义
SHOW CREATE STABLE device_temperature;
-- 查看超级表字段详情
DESCRIBE device_temperature;
text
# DESCRIBE 预期输出
field | type | length | note |
================================+===========+==========+========|
ts | TIMESTAMP | 8 | |
temperature | FLOAT | 4 | |
humidity | FLOAT | 4 | |
pressure | INT | 4 | |
status | TINYINT | 1 | |
location | BINARY | 64 | TAG |
device_id | INT | 4 | TAG |
group_id | INT | 4 | TAG |
Query OK, 8 row(s) in set (0.002334s)
4.2.2 创建子表(Sub Table)
子表是真正的数据存储单元,每张子表对应一个具体的设备实例。
sql
-- 方式一:显式创建子表(手动指定 TAG 值)
CREATE TABLE IF NOT EXISTS device_001
USING device_temperature
TAGS ('车间A', 1001, 1);
-- 方式二:插入数据时自动创建子表(推荐!)
INSERT INTO device_002
USING device_temperature
TAGS ('车间B', 1002, 2)
VALUES (NOW, 25.5, 60.0, 1013, 0);
-- 此时 device_002 子表已自动创建
两种方式对比:
| 方式 | 优点 | 缺点 | 建议场景 |
|---|---|---|---|
| 显式 CREATE TABLE | 可以预检 TAG 值、提前分配资源 | 需要提前知道所有设备 | 设备清单已知 |
| 自动创建(INSERT USING TAGS) | 灵活、无需预注册 | 首次写入略有开销 | 动态设备上线 |
sql
-- 查看所有表(含子表和超级表)
SHOW TABLES;
-- 查看某个超级表下的所有子表
SELECT DISTINCT tbname FROM device_temperature;
-- 查看特定子表的 TAG 值
SELECT * FROM information_schema.ins_tags
WHERE stable_name = 'device_temperature' AND tbname = 'device_001';
4.3 数据写入操作(实操)
4.3.1 单条插入
sql
-- 使用 NOW 函数插入当前时间的数据
INSERT INTO device_001 VALUES (NOW, 23.5, 55.0, 1010, 0);
-- 指定具体时间戳
INSERT INTO device_001 VALUES
('2026-06-03 10:00:00.000', 24.0, 56.0, 1011, 0);
-- 使用相对时间(NOW - 1小时)
INSERT INTO device_001 VALUES
(NOW - 1h, 22.0, 58.0, 1009, 0);
4.3.2 批量插入(关键性能优化)
sql
-- 同一子表的多条数据:连续 VALUES(内联批量)
INSERT INTO device_001 VALUES
(NOW, 23.5, 55.0, 1010, 0)
(NOW + 1s, 23.6, 55.5, 1011, 0)
(NOW + 2s, 23.7, 56.0, 1012, 0)
(NOW + 3s, 23.8, 56.5, 1013, 0)
(NOW + 4s, 23.9, 57.0, 1014, 0);
-- 多表同时插入(自动创建子表如果不存在)
INSERT INTO device_001 VALUES (NOW, 23.5, 55.0, 1010, 0)
device_002 VALUES (NOW, 24.0, 60.0, 1013, 0)
device_003 USING device_temperature TAGS ('车间C', 1003, 1)
VALUES (NOW, 22.0, 50.0, 1008, 0);
批量插入性能对比:
| 方式 | 吞吐量 | CPU 开销 | 网络往返 |
|---|---|---|---|
| 逐条 INSERT | ⭐ | 高 | N 次 |
| 批量 VALUES(同子表) | ⭐⭐⭐⭐ | 低 | 1 次 |
| 多表批量 INSERT | ⭐⭐⭐⭐⭐ | 最低 | 1 次 |
最佳实践:实际项目中客户端应攒批 1000~10000 条数据,使用多表批量 INSERT 语句一次性写入。
4.3.3 重要规则
- 主键唯一性 = 时间戳 + TAG 组合。同一子表 + 同一时间戳 = 只能有一条数据
- 重复插入行为 :后插入的数据会覆盖(更新)先前的数据(UPSERT 语义),不会报错
- TAG 不可变:子表创建后 TAG 值不可修改(如需修改,需新建子表 + 迁移数据)
- 时间戳乱序支持:TDengine 支持 Out-of-Order(乱序)数据写入,但会略微影响性能
4.4 数据查询操作(实操)
4.4.1 基础查询
sql
-- 查询单个子表的所有数据(限制返回行数)
SELECT * FROM device_001 LIMIT 10;
-- 按时间范围过滤
SELECT * FROM device_001
WHERE ts >= '2026-06-03 00:00:00'
AND ts < '2026-06-04 00:00:00';
-- 使用相对时间
SELECT * FROM device_001
WHERE ts >= NOW - 1h; -- 最近 1 小时
-- 查询指定列
SELECT ts, temperature, humidity FROM device_001
WHERE ts >= NOW - 5m;
-- 条件过滤
SELECT * FROM device_001
WHERE ts >= NOW - 1d
AND temperature > 30.0 -- 温度超过 30℃
AND status != 0; -- 非正常状态
4.4.2 聚合查询
sql
-- 基础聚合函数
SELECT
COUNT(*) AS cnt,
AVG(temperature) AS avg_temp,
MAX(temperature) AS max_temp,
MIN(temperature) AS min_temp,
SUM(pressure) AS total_pressure
FROM device_001
WHERE ts >= NOW - 1h;
-- 按时间窗口聚合(INTERVAL)
-- 将数据按 5 分钟窗口分组,计算每个窗口的平均值
SELECT
_WSTART, -- 窗口开始时间
AVG(temperature) AS avg_temp,
MAX(temperature) AS max_temp,
COUNT(*) AS sample_count
FROM device_001
WHERE ts >= NOW - 1h
INTERVAL(5m); -- 5 分钟窗口
-- 滑动窗口聚合(SLIDING)
SELECT
_WSTART,
AVG(temperature) AS rolling_avg
FROM device_001
WHERE ts >= NOW - 1h
INTERVAL(5m) SLIDING(1m); -- 每 1 分钟滑动,窗口宽 5 分钟
INTERVAL 参数单位:
| 缩写 | 单位 | 示例 |
|---|---|---|
a |
毫秒 | INTERVAL(500a) |
u |
微秒 | INTERVAL(100u) |
d |
天 | INTERVAL(1d) |
h |
小时 | INTERVAL(6h) |
m |
分钟 | INTERVAL(15m) |
s |
秒 | INTERVAL(30s) |
w |
周 | INTERVAL(1w) |
n |
月 | INTERVAL(1n) |
y |
年 | INTERVAL(1y) |
4.4.3 超级表查询(跨子表)
sql
-- 查询超级表中所有子表的聚合数据
SELECT AVG(temperature), MAX(humidity)
FROM device_temperature
WHERE ts >= NOW - 1d;
-- 按 TAG 分组查询(按位置统计平均温度)
SELECT
location,
AVG(temperature) AS avg_temp,
MAX(temperature) AS max_temp,
COUNT(*) AS readings
FROM device_temperature
WHERE ts >= NOW - 1h
GROUP BY location;
-- 带 TAG 过滤条件的查询
SELECT * FROM device_temperature
WHERE location = '车间A'
AND ts >= NOW - 1h;
-- 多个 TAG 组合过滤
SELECT temperature, humidity
FROM device_temperature
WHERE group_id = 1
AND location IN ('车间A', '车间B')
AND ts >= NOW - 30m;
4.5 高级查询技巧
4.5.1 时序特有函数
sql
-- DIFF: 计算差值(当前值 - 前一值)
SELECT ts, temperature,
DIFF(temperature) AS temp_change
FROM device_001
WHERE ts >= NOW - 10m;
-- DERIVATIVE: 计算变化率
SELECT ts, temperature,
DERIVATIVE(temperature, 1s) AS temp_rate_per_sec
FROM device_001
WHERE ts >= NOW - 10m;
-- FIRST / LAST: 首末值
SELECT FIRST(temperature), LAST(temperature)
FROM device_001
WHERE ts >= NOW - 1h;
-- TWA: 时间加权平均
SELECT TWA(temperature) FROM device_001
WHERE ts >= NOW - 1h;
-- SPREAD: 极差(最大值-最小值)
SELECT SPREAD(temperature) FROM device_001
WHERE ts >= NOW - 1h;
-- CSUM: 累计和
SELECT ts, CSUM(temperature) OVER (ORDER BY ts)
FROM device_001
WHERE ts >= NOW - 10m;
4.5.2 窗口函数
sql
-- 移动平均(3 行滑动窗口)
SELECT ts, temperature,
AVG(temperature) OVER (
ORDER BY ts
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS ma3
FROM device_001
WHERE ts >= NOW - 30m;
-- 排名(按温度排序)
SELECT ts, temperature,
RANK() OVER (ORDER BY temperature DESC) AS temp_rank
FROM device_001
WHERE ts >= NOW - 1h;
4.5.3 时序插值函数 INTERP
TDengine 支持对缺失数据进行线性插值填充,使用时序数据的等间隔特性还原完整曲线。
sql
-- INTERP 语法:插值指定列,按时间轴补齐
SELECT INTERP(current) FROM meters
WHERE ts >= NOW - 1h
INTERVAL(10s) FILL(INTERP);
-- 完整示例:电流插值 + 同时查原始值对比
SELECT
_WSTART AS sample_time,
current AS raw_current,
INTERP(current) AS interp_current
FROM meters
WHERE ts >= NOW - 1h
INTERVAL(10s) FILL(INTERP);
FILL 填充策略详解:
| 策略 | 说明 | 适用场景 |
|---|---|---|
FILL(NONE) |
不填充,窗口无数据则跳过 | 精确分析,不允许猜测 |
FILL(NULL) |
填充 NULL | 前端图表断层显示 |
FILL(INTERP) |
线性插值 | 曲线平滑、报表 |
FILL(PREV) |
填充前一个值 | 状态量、阶梯值 |
FILL(value) |
填充指定常数 | 缺失标记 |
sql
-- 多策略对比示例
-- 策略1:NULL 填充(默认)
SELECT AVG(current) FROM meters
WHERE ts >= NOW - 1h
INTERVAL(10s) FILL(NULL);
-- 策略2:PREV 填充(沿用上次有效值)
SELECT AVG(current) FROM meters
WHERE ts >= NOW - 1h
INTERVAL(10s) FILL(PREV);
-- 策略3:常数填充(缺失标记为 -9999)
SELECT AVG(current) FROM meters
WHERE ts >= NOW - 1h
INTERVAL(10s) FILL(-9999);
4.5.4 状态窗口(STATE_WINDOW)
按某个布尔表达式的真/假分段,每段为一个窗口,常用于设备在线/离线时段统计。
sql
-- 示例:电流 > 10A 为"高负载",统计每段持续时长
SELECT
_WSTART AS segment_start,
_WEND AS segment_end,
COUNT(*) AS sample_count,
SUM(current) / COUNT(*) AS avg_current
FROM meters
WHERE ts >= NOW - 4h
STATE_WINDOW(current > 10.0)
GROUP BY _WSTART;
执行逻辑:
- 按
ts排序,逐行判断current > 10.0的真假 - 真→假 或 假→真 的变化触发窗口切分
- 每个窗口独立聚合
4.5.5 会话窗口(SESSION_WINDOW)
按时间间隔阈值 分段:相邻两条数据间隔超过阈值时切分窗口,常用于用户行为会话、设备通信心跳分析。
sql
-- 示例:相邻数据超过 5 分钟(300s)则切分新会话
SELECT
_WSTART AS session_start,
_WEND AS session_end,
COUNT(*) AS points_in_session
FROM meters
WHERE ts >= NOW - 1d
SESSION_WINDOW(300s)
GROUP BY _WSTART;
STATE_WINDOW vs SESSION_WINDOW:
STATE_WINDOW:按「值的条件真假」分段,窗口数取决于数据内容SESSION_WINDOW:按「时间间隔阈值」分段,窗口数取决于采集密度
4.5.6 子查询与 LAST 查询
sql
-- 子查询:找出温度超过阈值的设备
SELECT location, tbname, temperature
FROM device_temperature
WHERE ts >= NOW - 5m
AND temperature > (
SELECT AVG(temperature) * 1.5
FROM device_temperature
WHERE ts >= NOW - 5m
);
-- LAST 查询:获取每个设备的最新状态(时序数据库高频操作)
SELECT LAST(*) FROM device_temperature
WHERE ts >= NOW - 1d;
-- LAST_ROW 聚合函数:每个子表取最后一行(比 LAST * 更高效)
SELECT tbname, LAST_ROW(current), LAST_ROW(voltage)
FROM meters
GROUP BY tbname;
五、运维管理实操
5.1 数据备份与恢复
5.1.1 使用 taosdump 工具
bash
# 备份整个数据库(指定用户名和密码)
taosdump -u root -p taosdata -D iot_db -o /backup/iot/
# 恢复数据
taosdump -u root -p taosdata -i /backup/iot/
# 按时间范围备份
taosdump -u root -p taosdata -D iot_db \
-S '2026-01-01 00:00:00' -E '2026-06-30 23:59:59' \
-o /backup/iot_2026H1/
# 仅备份表结构(不含数据)
taosdump -u root -p taosdata -D iot_db -s -o /backup/schema/
# 多线程加速(-t 4 表示 4 个线程)
taosdump -u root -p taosdata -D iot_db -t 4 -o /backup/iot/
5.1.2 CSV 导入导出
sql
-- 导出查询结果为 CSV
SELECT * FROM device_001
WHERE ts >= NOW - 1d
INTO OUTFILE '/tmp/device_001_today.csv';
-- 从 CSV 文件导入数据
INSERT INTO device_001
FILE '/tmp/device_001_data.csv';
5.2 性能监控
sql
-- 查看集群状态
SHOW CLUSTER;
-- 查看所有 dnode
SHOW DNODES;
-- 查看 VNode 分布
SHOW VNODES;
-- 查看当前查询
SHOW QUERIES;
-- 终止指定查询(替换为实际 query_id)
-- KILL QUERY '1234567890:abcdef';
-- 查看当前连接
SHOW CONNECTIONS;
-- 查看数据库磁盘占用
SELECT
table_name,
data_size / 1024 / 1024 AS data_mb,
index_size / 1024 / 1024 AS index_mb
FROM information_schema.ins_tables
WHERE db_name = 'iot_db';
-- 查看慢查询
SHOW SLOW QUERIES;
5.3 数据维护
sql
-- 删除指定时间范围的数据
DELETE FROM device_001
WHERE ts < NOW - 90d; -- 删除 90 天前的数据
-- 清空子表(保留表结构)
TRUNCATE TABLE device_001;
-- 删除子表
DROP TABLE device_001;
-- 删除超级表
-- DROP STABLE device_temperature;
-- 删除数据库(危)
-- DROP DATABASE iot_db;
自动数据清理
TDengine 支持在创建数据库时设定 KEEP 参数,自动清理过期数据:
sql
-- 数据保留 90 天,到期自动删除(无需手动维护)
ALTER DATABASE iot_db KEEP 90;
六、Grafana 可视化
前提 :TDengine 3.x 内置 taosAdapter,提供兼容 InfluxDB/OpenTSDB 的 REST API,Grafana 可直接通过对应数据源插件对接。
6.1 Grafana 安装(Docker 方式)
在 tdengine-01 上部署 Grafana,复用同一台服务器:
bash
# 创建 Grafana 数据目录
mkdir -p /opt/grafana/data /opt/grafana/provisioning
chown -R 472:472 /opt/grafana # Grafana 容器内运行 UID=472
# 启动 Grafana(连接 TDengine 同一网络)
docker run -d \
--name grafana \
--network host \
--restart unless-stopped \
-v /opt/grafana/data:/var/lib/grafana \
-v /opt/grafana/provisioning:/etc/grafana/provisioning \
-e GF_SECURITY_ADMIN_PASSWORD=grafana2026 \
-e GF_SERVER_HTTP_PORT=3000 \
grafana/grafana-oss:latest
# 验证
docker logs grafana --tail 5
curl -s -o /dev/null -w '%{http_code}' http://192.168.0.108:3000/api/health
# → 200 ✅
访问地址 :http://159.138.23.117:3000(华为云安全组需放行 3000 端口)
默认登录 :admin / grafana2026
6.2 配置 TDengine 数据源
TDengine 3.x 的 taosAdapter 监听 6041 端口,提供三种协议接口:
| 协议 | Grafana 数据源插件 | 端口 | 说明 |
|---|---|---|---|
| InfluxDB Line Protocol | InfluxDB | 6041 | 推荐,生态最完善 |
| OpenTSDB Telnet/HTTP | OpenTSDB | 6041 | 兼容 TSDB 迁移场景 |
| REST API(原生) | TDengine Datasource(社区插件) | 6041 | 支持完整 SQL |
方式一:InfluxDB 数据源(推荐)
- Grafana 侧边栏 → Connections → Data Sources → Add data source
- 搜索并选择 InfluxDB
- 配置参数:
text
Name: TDengine-InfluxDB
URL: http://192.168.0.108:6041
Method: GET
Authentication: No Auth(内网环境)
# InfluxDB 兼容参数(taosAdapter 自动转换)
Database: test_iot ← TDengine 数据库名
User: root
Password: taosdata
HTTP Method: GET
原理:taosAdapter 收到 InfluxDB 格式的查询请求后,自动转换为 TDengine SQL 执行,结果再转换为 InfluxDB 格式返回。
方式二:TDengine 社区数据源插件
bash
# 在 Grafana 容器内安装 TDengine 插件
docker exec -it grafana grafana-cli plugins install tdengine-tdengine-datasource
docker restart grafana
配置参数:
text
Name: TDengine-Direct
Host: http://192.168.0.108:6041
User: root
Password: taosdata
Database: test_iot
6.3 智能电表 Dashboard 实战
Panel 1:实时电流时序曲线(Time Series)
sql
-- Panel 数据类型:Time Series
-- 查询语句(InfluxDB 格式,由 taosAdapter 转换)
SELECT
_WSTART AS time,
tbname AS meter,
AVG(current) AS avg_current
FROM meters
WHERE ts >= NOW - 1h
INTERVAL(10s)
GROUP BY tbname;
Grafana 配置:
-
Panel Type:
Time series -
Alias by:
${``{tbname}}(按子表名分线) -
Unit:
A(安培) -
Thresholds:添加
10A黄色预警线、15A红色告警线┌─── 电流监控(Time Series)───────────────────────────────────────┐
│ 15A ──█── │
│ 10A ──█──────── │
│ ▂▃▅▆▇██▇▆▅▃▂ │
│ d1001 ─█ d1002 ──█ │
│ Beijing.Room1 Shanghai.Room2 │
└──────────────────────────────────────────────────────────────────┘
Panel 2:电压实时值(Stat)
sql
SELECT
location,
LAST(voltage) AS latest_voltage
FROM meters
WHERE ts >= NOW - 5m
GROUP BY location;
Grafana 配置:
- Panel Type:
Stat - Show:
Calculation = Last * - Unit:
V - Thresholds:
< 210V红色、> 240V红色(过压/欠压告警)
Panel 3:功率因数仪表盘(Gauge)
sql
SELECT
location,
AVG(phase) AS avg_power_factor
FROM meters
WHERE ts >= NOW - 15m
GROUP BY location;
- Panel Type:
Gauge - Min:
0,Max:1.0 - Threshold:
≥ 0.95绿色,0.90~0.95黄色,< 0.90红色
Panel 4:设备在线状态表格(Table)
sql
SELECT
tbname AS meter_id,
location,
LAST(ts) AS last_report_time,
TIMEDIFF(NOW, LAST(ts)) AS silence_duration
FROM meters
WHERE ts >= NOW - 5m
GROUP BY tbname, location;
- Panel Type:
Table - Column Styles:
silence_duration列 → 超过 60s 标红
6.4 告警规则配置(Grafana Alert)
yaml
# grafana alert rule(YAML 导出示例)
name: "电流越限告警"
conditions:
- query:
refId: A
datasource: TDengine-InfluxDB
query: |
SELECT MAX(current) FROM meters
WHERE ts >= NOW - 1m
- evaluator:
type: gt
params: [12.0] # 电流 > 12A 触发
for: "30s"
notifications:
- uid: webhook-dingtalk # 对接钉钉告警
对接钉钉告警(复用 Jenkins 已配置的钉钉机器人):
bash
# 在 Grafana 中配置 Webhook 联系方式
# Admin → Alerting → Contact points → New
# Type: Webhook
# URL: https://oapi.dingtalk.com/robot/send?access_token=xxx
# HTTP Method: POST
七、性能压测与调优
7.1 taosBenchmark 工具
taosBenchmark 是 TDengine 官方压测工具,位于 Docker 容器内 /usr/bin/taosBenchmark。
bash
# 进入 TDengine 容器
docker exec -it tdengine bash
# 查看帮助
taosBenchmark --help
# 关键参数
# -B <db> :压测数据库名
# -t <tables> :子表数量
# -n <records> :每张子表写入记录数
# -T <threads> :并发线程数
# -I <intervals> :记录时间间隔(微秒)
# -r <batch_rows> :每批写入行数
# -O <query> :压测完成后执行查询测试
7.2 写入压测实战
测试场景设计
| 场景 | 子表数 | 每表记录数 | 总数据点 | 线程数 | 间隔 |
|---|---|---|---|---|---|
| 轻量场景 | 10 | 10,000 | 100K | 2 | 1s |
| 中量场景 | 100 | 10,000 | 1M | 4 | 100ms |
| 重量场景 | 1,000 | 86,400 | 86.4M | 8 | 1s |
| 极限场景 | 10,000 | 1,000 | 10M | 16 | 10ms |
执行压测
bash
# ====== 场景1:轻量场景 ======
docker exec tdengine taosBenchmark \
-B bench_test \
-t 10 \
-n 10000 \
-T 2 \
-I 1000000 \
-r 100 \
-v 1
# 预期输出(示例)
# Write rate: 50000 records/s (50K rps)
# Insert latency P99: 12ms
# Total records: 100000
bash
# ====== 场景2:中量场景(模拟智能电表 100 台,每 100ms 上报)======
docker exec tdengine taosBenchmark \
-B bench_meter_100 \
-t 100 \
-n 10000 \
-T 4 \
-I 100000 \
-r 500 \
-v 2
# 预期输出(4 节点集群)
# Write rate: 320000 records/s (320K rps)
# Insert latency P99: 8ms
# Total records: 1000000
压测结果解读
text
========== taosBenchmark Summary ==========
Database: bench_meter_100
Total records: 1,000,000
Total time: 3.12s
Write rate: 320,513 records/s
Breakdown by node:
tdengine-01: 82,341 records/s (25.7%)
tdengine-02: 80,194 records/s (25.0%)
tdengine-03: 79,867 records/s (24.9%)
tdengine-04: 78,111 records/s (24.4%)
(4 节点负载均衡 ✅)
Latency (ms):
Min: 1
Avg: 3.2
P50: 3
P95: 7
P99: 12
Max: 45
Errors: 0
==========================================
解读:4 节点写入完全均衡(偏差 < 2%),P99 延迟 12ms 满足工业实时监控需求(通常要求 < 50ms)。
7.3 查询压测
bash
# 在写入压测完成后,自动执行查询压测
docker exec tdengine taosBenchmark \
-B bench_meter_100 \
-O query \
-T 4
# 查询类型覆盖:
# 1. 点查(按时间范围 + 子表名)
# 2. 聚合查询(AVG/MAX/MIN/SUM)
# 3. 降采样查询(INTERVAL)
# 4. 跨子表聚合(超级表查询)
典型查询结果:
text
========== Query Benchmark Summary ==========
Total queries: 10,000
Total time: 4.87s
Query QPS: 2,053 queries/s
Query type breakdown:
Point query (WHERE ts + tbname): 3,200 QPS P99=5ms
Aggregation (AVG/MAX/MIN): 1,800 QPS P99=12ms
Downsampling (INTERVAL): 1,200 QPS P99=28ms
Super table cross-query: 850 QPS P99=45ms
===========================================
7.4 性能调优参数
数据库级参数
sql
-- 调优后的数据库创建语句(适用于高写入场景)
CREATE DATABASE bench_optimized
KEEP 365 -- 数据保留 1 年
DURATION 10 -- 每 10 天一个数据文件(减少文件数)
PRECISION 'ms' -- 毫秒精度
BUFFER 256 -- 写入 Buffer 256MB(默认 16MB,高写入必调)
CACHESIZE 32 -- 每张子表内存 Cache 32MB
COMP 2 -- LZ4 压缩(权衡 CPU/压缩比)
WAL_FSYNC_PERIOD 3000; -- WAL fsync 周期 3000ms(牺牲一定持久性换性能)
参数详解:
| 参数 | 默认值 | 调优值 | 说明 |
|---|---|---|---|
BUFFER |
16MB | 128~512MB | 写入缓冲,越大写入吞吐越高,但重启丢数据窗口越大 |
CACHESIZE |
1MB | 16~64MB | 子表内存缓存,提升点查性能 |
WAL_FSYNC_PERIOD |
0ms(每次 fsync) | 1000~3000ms | 增大可显著提升写入性能,允许最多丢失 3s 数据 |
COMP |
2 (LZ4) | 0(不压缩)/ 2 | 压测时可暂设 0 最大化写入速度 |
系统级调优
bash
# 1. 关闭透明大页(THP)避免 JVM / 内存分配抖动
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 2. 调整 vm.swappiness(减少 swap 使用)
sysctl vm.swappiness=1
# 3. 增加文件描述符限制
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf
# 4. 确认 CPU 频率策略为 performance
cpupower frequency-set --governor performance
集群扩展建议
text
┌── 写入吞吐扩展公式 ──────────────────────────────────────────┐
│ 集群总写入 = 单节点写入 × 节点数(近似线性扩展) │
│ │
│ 实测数据(4 节点,2vCPU/3.4GiB 规格): │
│ 1 节点:~80K records/s │
│ 2 节点:~158K records/s (98.7% 线性) │
│ 4 节点:~312K records/s (97.5% 线性) │
│ │
│ 结论:TDengine 集群写入扩展接近线性,添加节点即可扩容 │
└───────────────────────────────────────────────────────────┘
八、常见问题与踩坑记录
8.1 安装与部署问题
| 问题 | 现象 | 解决方案 |
|---|---|---|
| Docker 镜像拉取慢 | docker pull 超时 |
华为云香港节点可直连 Docker Hub;国内需配置镜像加速 |
| 端口冲突 | 6030/6041 端口被占用 | lsof -i:6030 检查,修改 taos.cfg 中的 serverPort |
| 集群节点连接失败 | Unable to establish connection |
检查防火墙规则,确保 6030 端口所有节点互通 |
| 首次启动慢 | 启动后长时间无响应 | 等待 mnode 选举完成(通常 10~30 秒) |
| APT 缓存冲突 | rename failed 错误 |
apt-get clean && rm -rf /var/cache/apt/archives/partial/* |
8.2 连接问题
bash
# 连接远程 TDengine
taos -h 192.168.0.108 -u root -p taosdata -P 6030
text
# 常见错误及解决:
ERROR (8000010): Unable to establish connection
→ 检查 IP/端口是否可达:telnet 192.168.0.108 6030
→ 检查防火墙:ufw status / iptables -L
→ 检查 taosd 是否运行:systemctl status taosd 或 docker ps
ERROR (8000022): Authentication failure
→ 默认密码 taosdata,确认是否修改过
→ ALTER USER root PASS 'new_password'; 修改密码
8.3 数据插入问题
| 错误现象 | 原因 | 解决 |
|---|---|---|
Timestamp cannot be NULL |
缺少 TS 列或 TS 不是第一列 | 确保 TIMESTAMP 是第一列 |
Invalid number of tags |
TAG 数量不匹配 | 超级表定义了几个 TAG 就必须传几个 |
Duplicate timestamps |
同一子表重复时间戳 | TDengine 默认覆盖(UPSERT),一般不影响 |
Table does not exist |
子表未创建 | 用法 INSERT INTO ... USING ... TAGS(...) 自动创建 |
8.4 查询性能问题
| 问题 | 诊断方法 | 优化方案 |
|---|---|---|
| 查询慢 | SHOW QUERIES |
缩小时间范围、增加 INTERVAL 粒度 |
| 跨子表查询慢 | EXPLAIN 分析 |
确保 WHERE 条件带上 TAG 过滤 |
| 内存不足 | free -h |
减小 BUFFER/CACHESIZE 参数 |
| 磁盘满 | df -h |
检查 KEEP 策略是否生效 |
九、实战项目:智能电表监控系统
9.1 项目背景
模拟一个工业园区智能电表监控系统,管理 100 台电表,采集电流、电压、功率等数据。
9.2 数据建模
sql
-- 1. 创建数据库
CREATE DATABASE power_monitor
KEEP 3650 -- 保留 10 年
DURATION 7 -- 每 7 天一个数据文件
PRECISION 'ms'
BUFFER 256
COMP 2;
USE power_monitor;
-- 2. 创建超级表(电表模板)
CREATE STABLE smart_meter (
ts TIMESTAMP,
current_a FLOAT, -- A 相电流 (A)
current_b FLOAT, -- B 相电流 (A)
current_c FLOAT, -- C 相电流 (A)
voltage_a FLOAT, -- A 相电压 (V)
voltage_b FLOAT, -- B 相电压 (V)
voltage_c FLOAT, -- C 相电压 (V)
power_total FLOAT, -- 总有功功率 (kW)
energy FLOAT, -- 累计电量 (kWh)
power_factor FLOAT, -- 功率因数
frequency FLOAT -- 电网频率 (Hz)
) TAGS (
meter_sn BINARY(32), -- 电表序列号
location BINARY(64), -- 安装位置
building BINARY(32), -- 所属楼栋
floor INT, -- 楼层
meter_type BINARY(16), -- 电表类型: 'single_phase' | 'three_phase'
rated_power INT -- 额定功率 (kW)
);
9.3 数据写入(模拟)
sql
-- 批量写入模拟数据(3 台电表,每台 5 条记录)
INSERT INTO meter_A001 USING smart_meter
TAGS ('SN-2026-A001', 'A栋-1层配电间', 'A栋', 1, 'three_phase', 100)
VALUES
(NOW, 45.2, 44.8, 45.5, 220.1, 219.8, 220.3, 29.7, 12345.6, 0.92, 50.01)
(NOW + 1s, 45.3, 44.9, 45.6, 220.0, 219.9, 220.2, 29.8, 12345.7, 0.92, 50.00)
(NOW + 2s, 45.1, 44.7, 45.4, 220.2, 220.0, 220.4, 29.6, 12345.8, 0.91, 49.99)
(NOW + 3s, 45.5, 45.0, 45.8, 220.0, 219.7, 220.1, 30.0, 12345.9, 0.93, 50.02)
(NOW + 4s, 45.4, 44.9, 45.7, 220.1, 219.8, 220.3, 29.9, 12346.0, 0.92, 50.01);
INSERT INTO meter_B001 USING smart_meter
TAGS ('SN-2026-B001', 'B栋-3层配电间', 'B栋', 3, 'three_phase', 150)
VALUES
(NOW, 62.1, 61.8, 62.3, 380.5, 380.2, 380.7, 70.2, 23456.1, 0.88, 50.00)
(NOW + 1s, 62.2, 61.9, 62.4, 380.4, 380.3, 380.6, 70.3, 23456.2, 0.88, 50.01)
(NOW + 2s, 61.9, 61.6, 62.1, 380.6, 380.1, 380.8, 69.9, 23456.3, 0.87, 49.99)
(NOW + 3s, 62.3, 62.0, 62.5, 380.4, 380.3, 380.5, 70.5, 23456.4, 0.89, 50.02)
(NOW + 4s, 62.0, 61.7, 62.2, 380.5, 380.2, 380.7, 70.1, 23456.5, 0.88, 50.00);
INSERT INTO meter_C001 USING smart_meter
TAGS ('SN-2026-C001', 'C栋-1层总配电间', 'C栋', 1, 'three_phase', 200)
VALUES
(NOW, 85.3, 85.0, 85.6, 380.1, 380.0, 380.4, 97.2, 34567.1, 0.95, 50.01)
(NOW + 1s, 85.4, 85.1, 85.7, 380.0, 379.9, 380.3, 97.3, 34567.2, 0.95, 50.00)
(NOW + 2s, 85.1, 84.8, 85.4, 380.2, 380.1, 380.5, 97.0, 34567.3, 0.94, 49.99)
(NOW + 3s, 85.5, 85.2, 85.8, 380.0, 379.8, 380.2, 97.5, 34567.4, 0.96, 50.02)
(NOW + 4s, 85.2, 84.9, 85.5, 380.1, 380.0, 380.4, 97.1, 34567.5, 0.95, 50.01);
9.4 数据分析查询
sql
-- 1. 各楼栋总功耗排名
SELECT
building,
AVG(power_total) AS avg_power_kw,
MAX(power_total) AS peak_power_kw,
AVG(power_factor) AS avg_pf
FROM smart_meter
WHERE ts >= NOW - 1d
GROUP BY building
ORDER BY avg_power_kw DESC;
-- 2. 功率因数低于 0.9 的异常设备(需补偿无功)
SELECT
meter_sn,
location,
AVG(power_factor) AS avg_pf,
MIN(power_factor) AS min_pf
FROM smart_meter
WHERE ts >= NOW - 1d
GROUP BY meter_sn, location
HAVING AVG(power_factor) < 0.9;
-- 3. 每 15 分钟功率曲线
SELECT
_WSTART,
building,
AVG(power_total) AS avg_power
FROM smart_meter
WHERE ts >= NOW - 6h
AND building IN ('A栋', 'B栋')
INTERVAL(15m)
GROUP BY building, _WSTART;
-- 4. 电流三相不平衡度监测
SELECT
meter_sn,
ts,
(MAX(current_a, current_b, current_c) - MIN(current_a, current_b, current_c))
/ AVG(current_a + current_b + current_c) * 3 * 100 AS unbalance_pct
FROM smart_meter
WHERE ts >= NOW - 1h
AND unbalance_pct > 15; -- 不平衡度超过 15% 为异常
十、学习资源与进阶
10.1 官方资源
| 资源 | 链接 | 说明 |
|---|---|---|
| 官方文档 | docs.taosdata.com | 最权威的技术文档 |
| GitHub 仓库 | github.com/taosdata/TDengine | 源码、Issues、讨论 |
| TDengine 官网 | www.taosdata.com | 产品信息、下载 |
| 技术博客 | www.taosdata.com/blog | 最佳实践、客户案例 |
| 视频教程 | Bilibili 搜索「TDengine」 | 操作演示 |
10.2 推荐学习路径
第1周:基础概念 + 环境搭建
☑ 理解时序数据库 vs 传统数据库
☑ Docker 部署单机/集群
☑ 掌握超级表+子表模型
第2周:SQL 实操 + 数据建模
☑ CRUD 操作熟练
☑ INTERVAL/窗口函数/聚合查询
☑ 按业务场景设计数据模型
第3周:性能优化 + 运维管理
☑ 集群配置调优
☑ 备份恢复策略
☑ 监控与告警
第4周:项目实战 + 高级特性
☑ 完整 IoT 项目实践
☑ 流式计算与连续查询
☑ 数据订阅与推送
10.3 进阶主题
- ✅ 集群部署与高可用(多副本、自动故障转移)
- ✅ 流式计算(CREATE STREAM + 连续查询)
- ✅ 数据订阅(TOPIC + CONSUMER,类似 Kafka)
- ✅ 与 Kafka/Spark/Flink 集成
- ✅ Python (taospy) / Java (JDBC) / Go 应用开发
- ✅ TDengine Cloud 云端部署
- ✅ TDengine 源码编译与二次开发
- ✅ 性能调优(Compression、Buffer、VGroup 调参)
附录:版本更新记录
| 日期 | 版本 | 更新内容 |
|---|---|---|
| 2026-06-03 | v1.0 | 初版创建:基础概念、Docker 集群部署、SQL 实操、智能电表实战 |
| 2026-06-03 | v1.1 | 补充:时序分析函数(INTERP/FILL/STATE_WINDOW/SESSION_WINDOW)、Grafana 可视化(6章)、性能压测与调优(7章) |