TDengine SQL 与标准 SQL 差异 — 时序数据库的特殊性
分类:10.SQL 参考 |篇章:08 SQL 差异
>适用版本:TDengine v3.x(v3.3.x / v3.4.x) | 最后更新:2026-07-22
点击了解免费详情
TDengine 兼容大部分标准 SQL 但有时序特性扩展和限制。本文系统列出与 MySQL/PostgreSQL 等关系数据库的核心差异,帮助迁移和误用排查。
核心差异概览
| 维度 | 标准 SQL | TDengine |
|---|---|---|
| 主键 | 任意类型 | 必须 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 BETWEEN4. 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 -- 必须含 ts5. 索引
标准 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 写法CREATETABLEsensors(idINTPRIMARYKEYAUTO_INCREMENT,device_idVARCHAR(50),tsDATETIME,valueDOUBLE,INDEXidx_device(device_id));INSERTINTOsensorsVALUES(1,'d001','2026-06-04 12:00',25.3);-- TDengine 改写CREATESTABLE sensors(tsTIMESTAMP,valueDOUBLE)TAGS(device_idVARCHAR(50));CREATETABLEd001USINGsensors TAGS('d001');INSERTINTOd001VALUES('2026-06-04 12:00:00',25.3);-- 或自动建表:INSERTINTOd001USINGsensors TAGS('d001')VALUES('2026-06-04 12:00:00',25.3);查询改写
-- MySQL ROW_NUMBERSELECT*,ROW_NUMBER()OVER(PARTITIONBYdevice_idORDERBYtsDESC)ASrnFROMsensorsWHERErn=1;-- TDengine 改写:用 LAST_ROWSELECTLAST_ROW(*)FROMsensorsPARTITIONBYtbname;-- MySQL LAGSELECTts,value,LAG(value)OVER(PARTITIONBYdevice_idORDERBYts)ASprevFROMsensors;-- TDengine 改写:用 DIFFSELECTts,value,value-DIFF(value)ASprevFROMsensors;-- 或不直接计算 LAG,用 DIFF 表示变化-- MySQL MERGEMERGEINTOtargetUSINGsourceONtarget.id=source.idWHENMATCHEDTHENUPDATESETval=source.valWHENNOTMATCHEDTHENINSERT(id,val)VALUES(source.id,source.val);-- TDengine 改写:INSERTINTOtargetSELECT*FROMsource;-- ts 主键天然去重窗口改写
-- 标准 OVER 窗口SELECTid,ts,AVG(val)OVER(ORDERBYtsROWSBETWEEN5PRECEDINGANDCURRENTROW)ASrollingFROMt;-- TDengine MAVGSELECTts,MAVG(val,6)ASrollingFROMt;-- 标准 PARTITION BY ts BUCKETSELECTTIMESTAMP_BUCKET(ts,INTERVAL'1 hour')ASh,AVG(val)FROMtGROUPBYh;-- TDengine INTERVALSELECT_wstart,AVG(val)FROMtINTERVAL(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:业务元数据
- 应用层组合查询
参考
系统构架篇
- 01-《TDengine 整体架构全景》
- 02-《集群拓扑深度解析》
- 03-《MNode 内部机制深度解析》
- 04-《RPC 通信层深度解析》
- 05-《VNode 生命周期》
- 06-《RAFT 共识协议》
- 07-《端到端的消息流》
数据模型
- 01-《数据库创建与参数详解》
- 02-《超级表/子表/普通表》
- 03-《支持数据类型深度解析》
- 04-《TDengine Tag 设计哲学与 Schema 变更机制》
- 05-《TDengine 虚拟表实现原理》
存储引擎
- 01-《TDengine 存储引擎概览》
- 02-《TDengine MemTable 深度解析》
- 03-《TDengine WAL 预写日志机制》
- 04-《TDengine 数据文件格式》
- 05-《TDengine Commit 与 Flush 机制 》
- 06-《TDengine Compaction 合并策略 》
- 07-《TDengine 数据保留与 TTL》
- 08-《TDengine 压缩编码机制》
- 09-《TDengine Cache 与 Last 查询加速》
- 10-《TDengine 逻辑计划生成》
查询引擎
- 01-《TDengine 查询引擎概览》
- 02-《TDengine SQL 解析与词法分析》
- 03-《TDengine 语义分析与 AST 重写》
- 04-《TDengine 逻辑计划生成》
- 05-《TDengine 物理计划生成》
- 06-《TDengine 扫描算子》
- 07-《TDengine 聚合算子》
- 08-《TDengine 连接算子》
- 09-《TDengine 排序、填充与投影》
- 10-《TDengine 分布式查询执行》
- 11-《TDengine EXPLAIN 与查询优化》
数据写入
- 01-《TDengine SQL INSERT》
- 02-《TDengine 无模式写入》
- 03-《TDengine STMT 写入》
- 04-《TDengine 写入内部流程》
- 05-《TDengine 数据更新删除》
数据订阅
- 01-《TDengine 数据订阅》
- 02-《TDengine 订阅 vs Kafka》
- 03-《TDengine TMQ 消费流程》
- 04-《TDengine 内部机制》
- 05-《TDengine TMQ 最佳实践》
预聚合
- 01-《TDengine RSMA》
- 02-《TDengine TSMA — 时间维度的物化聚合视图》
- 03-《TDengine SMA 内部实现》
索引
- 01-《TDengine Tag 索引》
- 02-《TDengine SMA 索引》
SQL 语句
- 01-《TDengine DDL》
- 02-《TDengine DML SELECT》
- 03-《TDengine DML 函数完整参考》
- 04-《TDengine JOIN 完整语法》
- 05-《TDengine 窗口完整语法》
- 06-《TDengine 操作符与表达式》
- 07-《TDengine 系统表》
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。
