TDengine SQL 与标准 SQL 差异 — 时序数据库的特殊性

分类:10.SQL 参考 | 篇章:08 SQL 差异
在这里插入图片描述> 适用版本:TDengine v3.x(v3.3.x / v3.4.x) | 最后更新:2026-07-22

点击了解免费详情

TDengine 兼容大部分标准 SQL 但有时序特性扩展和限制。本文系统列出与 MySQL/PostgreSQL 等关系数据库的核心差异,帮助迁移和误用排查。

核心差异概览

维度标准 SQLTDengine
主键任意类型必须 ts (TIMESTAMP)
表组织单层超级表/子表/普通表
JOIN任意条件必须含时间条件
窗口OVER 窗口INTERVAL/SESSION/STATE/EVENT/COUNT
存储行式列式
Schema严格支持 Schemaless
索引任意列时间+Tag 自动
事务ACID单语句原子

详细解析

1. 主键与数据模型

标准 SQL:
  CREATE TABLE t (
    id INT PRIMARY KEY,
    name VARCHAR(100)
  );


TDengine:
  CREATE TABLE t (
    ts TIMESTAMP,         -- 必须是第一列
    val FLOAT
  );
  -- 时间列隐式为主键


超级表概念(无对应):
  TDengine 特有
  一组同构子表的模板
  Tag 作为标签维度

2. JOIN 限制

标准 SQL:
  SELECT * FROM t1 JOIN t2 ON t1.id = t2.id;
  -- 任意条件 OK

TDengine:
  SELECT * FROM t1 JOIN t2 ON t1.ts = t2.ts AND t1.id = t2.id;
  -- 必须有时间相关条件
  
  -- 替代方案:
  ASOF JOIN     -- 时间近邻
  WINDOW JOIN   -- 时间窗口

3. 窗口函数

标准 SQL(OVER 窗口):
  SELECT id, val, 
    AVG(val) OVER (PARTITION BY tag ORDER BY ts ROWS BETWEEN 5 PRECEDING AND CURRENT ROW) 
  FROM t;


TDengine(窗口子句):
  SELECT _wstart, AVG(val) 
  FROM t 
  PARTITION BY tag 
  INTERVAL(1h);
  
  -- 或 MAVG 函数
  SELECT ts, MAVG(val, 5) FROM t;
  
  -- 不支持 OVER ... ROWS BETWEEN

4. DELETE/UPDATE

标准 SQL:
  DELETE FROM t WHERE id = 1;
  UPDATE t SET val = 0 WHERE id = 1;
  -- 无时间约束


TDengine:
  DELETE FROM t WHERE ts > T1 AND ts < T2;
  -- 必须有时间范围条件
  
  UPDATE t SET val = 0 WHERE ts = '2026-06-04 12:00:00';
  -- ts 是主键,唯一定位行
  
  -- 不支持:
  WHERE val = 100         -- 必须含 ts

5. 索引

标准 SQL:
  CREATE INDEX idx ON t (name);
  CREATE INDEX idx ON t (name, age);  -- 组合索引


TDengine:
  -- 数据列无显式索引
  -- 块 SMA 自动统计
  
  -- Tag 索引:
  CREATE INDEX idx ON super_table (tag_column);
  
  -- 不支持组合索引
  -- 不支持函数索引

6. 事务与一致性

标准 SQL:
  BEGIN;
  INSERT INTO t1 ...;
  INSERT INTO t2 ...;
  COMMIT;
  -- ACID 事务


TDengine:
  -- 单语句原子(单 SQL 内全成或全败)
  INSERT INTO t1 ..., t2 ... ;   -- 跨表批量也原子
  
  -- 不支持:
  BEGIN/COMMIT/ROLLBACK
  跨语句事务
  
  -- 替代:业务层处理一致性

7. SELECT 限制

不支持/有限支持的特性:

  ① 复杂子查询:
     - 标量子查询有限
     - 关联子查询不支持
     
  ② OVER 窗口函数:
     - ROW_NUMBER/RANK/DENSE_RANK 不支持
     - LAG/LEAD 不支持(用 DIFF/MAVG 替代)
     
  ③ WITH RECURSIVE:
     - 不支持递归 CTE
     
  ④ MERGE / UPSERT:
     - 不支持 MERGE INTO
     - INSERT 天然按 ts 去重
     
  ⑤ FULL TEXT SEARCH:
     - 不内置全文检索

8. 数据类型差异

TDengine 特有:
  TIMESTAMP (主键)
  
TDengine 缺少:
  TEXT (大文本)         → 用 VARCHAR(N)
  BLOB (大二进制)       → 用 VARBINARY(N)
  DATE / TIME (单独)    → 都用 TIMESTAMP
  DECIMAL (精确小数)    → 用 DOUBLE / 整数缩放
  ENUM                  → 用 VARCHAR + 应用层约束
  ARRAY                 → 用 JSON 或拆列
  
注意:
  VARCHAR 长度按字节计(N 字节)
  NCHAR 按字符计(N 个 Unicode 字符)

代码示例

迁移示例

-- MySQL 写法
CREATE TABLE sensors (
  id INT PRIMARY KEY AUTO_INCREMENT,
  device_id VARCHAR(50),
  ts DATETIME,
  value DOUBLE,
  INDEX idx_device (device_id)
);

INSERT INTO sensors VALUES (1, 'd001', '2026-06-04 12:00', 25.3);

-- TDengine 改写
CREATE STABLE sensors (
  ts TIMESTAMP,
  value DOUBLE
) TAGS (
  device_id VARCHAR(50)
);

CREATE TABLE d001 USING sensors TAGS('d001');
INSERT INTO d001 VALUES ('2026-06-04 12:00:00', 25.3);
-- 或自动建表:
INSERT INTO d001 USING sensors TAGS('d001') 
VALUES ('2026-06-04 12:00:00', 25.3);

查询改写

-- MySQL ROW_NUMBER
SELECT *, ROW_NUMBER() OVER (PARTITION BY device_id ORDER BY ts DESC) AS rn 
FROM sensors WHERE rn = 1;

-- TDengine 改写:用 LAST_ROW
SELECT LAST_ROW(*) FROM sensors PARTITION BY tbname;


-- MySQL LAG
SELECT ts, value, LAG(value) OVER (PARTITION BY device_id ORDER BY ts) AS prev 
FROM sensors;

-- TDengine 改写:用 DIFF
SELECT ts, value, value - DIFF(value) AS prev FROM sensors;
-- 或不直接计算 LAG,用 DIFF 表示变化


-- MySQL MERGE
MERGE INTO target USING source ON target.id = source.id 
WHEN MATCHED THEN UPDATE SET val = source.val 
WHEN NOT MATCHED THEN INSERT (id, val) VALUES (source.id, source.val);

-- TDengine 改写:
INSERT INTO target SELECT * FROM source;
-- ts 主键天然去重

窗口改写

-- 标准 OVER 窗口
SELECT id, ts, 
  AVG(val) OVER (ORDER BY ts ROWS BETWEEN 5 PRECEDING AND CURRENT ROW) AS rolling 
FROM t;

-- TDengine MAVG
SELECT ts, MAVG(val, 6) AS rolling FROM t;


-- 标准 PARTITION BY ts BUCKET
SELECT TIMESTAMP_BUCKET(ts, INTERVAL '1 hour') AS h, AVG(val) 
FROM t GROUP BY h;

-- TDengine INTERVAL
SELECT _wstart, AVG(val) FROM t INTERVAL(1h);

性能考量

迁移性能预期

场景TDengine vs MySQL/PostgreSQL
单设备写入10x~50x
批量写入100x+
时序聚合查询10x~100x
任意 JOIN受限(设计上不擅长)
全文检索不支持
复杂 OLAP部分支持

设计原则

关系数据库习惯TDengine 改写
自增 ID 主键时间戳 + Tag
单表千万行拆分为超级表 + 子表
任意 JOIN限制为时间相关
OVER 窗口时序窗口函数
事务业务层处理

FAQ

Q1: 标准 SQL 哪些功能不支持?

主要不支持:复杂 OVER 窗口、递归 CTE、跨语句事务、全文检索、复杂关联子查询。

Q2: 应用迁移成本大吗?

  • 时序场景:迁移简单(90% SQL 可用)
  • 复杂 OLTP:不适合,应保留原数据库

Q3: 能用 ORM 框架吗?

支持 JDBC/ODBC/Python DB-API 等标准接口,主流 ORM 大多兼容。某些 ORM 的高级特性(如懒加载、复杂查询构造)需注意。

Q4: 时区怎么处理?

存储 UTC,客户端按时区显示。建议明确指定时区。

Q5: 能与现有关系数据库共存吗?

可以。常见架构:

  • TDengine:时序数据
  • MySQL/Postgres:业务元数据
  • 应用层组合查询

参考

系统构架篇

数据模型

存储引擎

查询引擎

数据写入

数据订阅

预聚合

索引

SQL 语句

关于 TDengine

TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TDengine (老段)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值