TDengine 超级表管理详解:CREATE / ALTER / DROP STABLE 语法、标签体系与底层实现
【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine
超级表(Super Table,简称 STable)是 TDengine 面向 IoT 场景设计的核心 DDL 对象:它定义了一组子表共享的表结构(数据列)与标签(Tags),使成千上万台设备的表能够以统一模式批量创建、按标签批量检索。本篇基于 TDengine 官方 SQL 参考中"超级表"一章,完整覆盖创建、查看、删除、修改超级表的全部语句语法与约束规则,并结合同仓库的元数据管理源码(mnode/mndStb)与测试用例,说明每条限制背后的实现依据。读完本文,你可以独立编写生产级的超级表 DDL,并理解 TDengine 在列数、标签数、行大小等维度上的硬性边界及其校验位置。
一、创建超级表(CREATE STABLE)
1.1 完整语法
CREATE STABLE [IF NOT EXISTS] [db_name.]stb_name (create_definition [, create_definition] ...) TAGS (create_definition [, create_definition] ...) [BASE ON [db_name.]parent_stb_name [, [db_name.]parent_stb_name] ...] [table_options] create_definition: col_name column_definition column_definition: type_name [COMPOSITE KEY] [ENCODE 'encode_type'] [COMPRESS 'compress_type'] [LEVEL 'level_type'] table_options: table_option ... table_option: { COMMENT 'string_value' | SMA(col_name [, col_name] ...) | KEEP value | VIRTUAL {0 | 1} }语法要点如下:
- 超级表名与列名遵循 TDengine 的名称命名规则(详见 名称命名规则)。
TAGS (...)是超级表区别于普通表的标志性子句,用于声明标签列集合。BASE ON用于虚拟超级表的列/标签继承(详见 虚拟超级表继承)。table_options支持COMMENT、SMA、KEEP、VIRTUAL,其中COMMENT、SMA等通用表选项的含义与 数据表 一致。
一个包含压缩选项与保留策略的完整示例:
CREATE STABLE meters (ts TIMESTAMP, voltage INT, current FLOAT, phase FLOAT) TAGS (group_id BINARY(10), location VARCHAR(24), device_id BINARY(32)) SMA(volatility(current, 10), volatility(voltage, 10), avg(current)) KEEP 3650;1.2 创建时的核心约束
(1)字段数量限制
- 非虚拟超级表:列 + 标签的总数最大
4096,且最少需要 3 个字段——一个TIMESTAMP主键列、一个数据列、一个标签列; - 虚拟超级表:数据列最多
32767,标签数量上限仍为128。
这些边界在元数据层的创建校验中被强制实施。从源码结构看,mndStb.c 中的mndCheckCreateStbReq会根据virtualStb标志选择不同的列数上限:
int32_t maxColumns = pCreate->virtualStb ? TSDB_MAX_COLUMNS : TSDB_MAX_COLUMNS_NON_VIRTUAL;对应的常量定义在 tdef.h:
#define TSDB_MAX_COLUMNS 32767 #define TSDB_MAX_COLUMNS_NON_VIRTUAL 4096修改结构(ALTER)时的校验同样以这两个常量为界(见 mndStb.c 中对maxColumns、maxBytesPerRow的判断),保证"创建"与"演进"两条路径遵守同一套约束。
(2)时间戳主键与复合主键
- 第一个字段必须是
TIMESTAMP类型,系统自动将其设为主键; - 除时间戳主键外,可用
COMPOSITE KEY将第二列声明为附加主键列。设置复合主键后,只有当两条记录的ts与COMPOSITE KEY列值都相同时才视为重复记录(只保留最新一条),否则视为两条记录全部保留; COMPOSITE KEY列必须是整型(INT、BIGINT、UINT、UBIGINT)或字符串类型(VARCHAR、BINARY)。
复合主键典型用于"同一时刻多条读数"的场景,例如一个设备每秒上报多条不同测点的瞬时值。
(3)标签(TAGS)约定
- 标签列名不能与数据列名重复,且不能是未转义的保留关键字;
- 标签最多
128个、至少1个,单表所有标签值总长度不超过16 KB; TAGS中的TIMESTAMP列在写入数据时必须提供确定值,暂不支持NOW + 10s这类表达式。
上限常量同样可在公共头文件中核实(tdef.h):
#define TSDB_MAX_BYTES_PER_ROW 65531 // 49151:65531 #define TSDB_MAX_BYTES_PER_ROW_VIRTUAL 524283 #define TSDB_MAX_TAGS_LEN 16384 #define TSDB_MAX_TAGS 128TSDB_MAX_TAGS_LEN = 16384即文档中"标签值总长度不超过 16 KB"的直接依据。此外 tdef.h 还定义了虚拟超级表继承相关的边界:TSDB_MAX_VTABLE_REF_DEPTH 32(继承引用深度上限)与TSDB_MAX_VST_PARENTS 10(父虚拟表数量上限),这解释了BASE ON列表中多父表的个数为何受到限制。
(4)按列压缩选项
ENCODE、COMPRESS、LEVEL用于为指定列选择编码与压缩算法,用法详见 按列压缩。注意虚拟超级表不支持压缩选项(见下文VIRTUAL说明)。
(5)超级表级 KEEP
KEEP仅对超级表生效,设置该超级表的数据保留时长。取值格式与数据库级 KEEP 一致(参见 数据库),但存在四点重要差异:
- 超级表
KEEP不会立即影响查询结果,只有执行数据重整后,过期数据才会被清理并对查询不可见; - 超级表
KEEP必须小于所在数据库的KEEP; - 数据重整前需要先执行
FLUSH,否则可能不生效; - 数据重整后再通过
ALTER STABLE修改KEEP并重新执行数据重整时,部分数据能否被清理,取决于对应文件在上次数据重整之后是否有新数据写入。
(6)VIRTUAL 选项
VIRTUAL 1创建虚拟超级表,VIRTUAL 0(默认)创建普通超级表;- 虚拟超级表的
column_definition仅支持type_name,不支持COMPOSITE KEY、ENCODE、COMPRESS、LEVEL等附加选项; - 虚拟超级表支持通过
BASE ON继承其他虚拟超级表的列和标签,详见 虚拟超级表继承。
创建校验逻辑中可以看到virtualStb对校验分支的影响:mndStb.c 会检查numOfTags、numParents与noOwnTags(无自有标签但存在父表)的组合是否合法,即"纯继承"的虚拟超级表可以不声明TAGS。
二、查看超级表
2.1 显示超级表
SHOW [db_name.]STABLES [LIKE 'pattern'];显示指定数据库(或当前数据库)下的所有超级表,可用LIKE对表名做模糊匹配。
2.2 显示创建语句(迁移利器)
SHOW CREATE STABLE [db_name.]stb_name;对已存在的超级表返回其创建语句,在另一集群中执行该语句即可得到一个结构完全相同的超级表——这是跨集群迁移表结构的标准手段。
2.3 获取结构信息
DESCRIBE [db_name.]stb_name;列出超级表的数据列与标签列定义。
2.4 获取超级表所有子表的标签信息
SHOW TABLE TAGS [tag_name [, tag_name] ...] FROM table_name [FROM db_name]; SHOW TABLE TAGS [tag_name [, tag_name] ...] FROM [db_name.]table_name;执行效果示例:
taos> SHOW TABLE TAGS FROM st1; tbname | id | loc | ====================================================================== st1s1 | 1 | beijing | st1s2 | 2 | shanghai | st1s3 | 3 | guangzhou | Query OK, 3 rows in database (0.004455s)结果集第一列为子表名,后续列为标签列。若已知标签列名,也可用SELECT DISTINCT获取指定标签列的值:
taos> SELECT DISTINCT TBNAME, id FROM st1; tbname | id | =============================================== st1s1 | 1 | st1s2 | 2 | st1s3 | 3 | Query OK, 3 rows in database (0.002891s)需要强调:SELECT语句中的DISTINCT与TBNAME缺一不可。TDengine 会识别这种"取子表名 + 去重"的模式并走元数据路径做专门优化,因此即使子表没有数据、或者子表数量极大,也能正确且快速地返回标签值——这正是标签体系"标签即维度、子表即实例"设计的体现。
2.5 获取某个子表的标签信息
taos> SHOW TAGS FROM st1s1; table_name | db_name | stable_name | tag_name | tag_type | tag_value | ============================================================================================================ st1s1 | test | st1 | id | INT | 1 | st1s1 | test | st1 | loc | VARCHAR(20) | beijing | Query OK, 2 rows in database (0.003684s)同样可以用SELECT DISTINCT查询指定子表单个标签列的值:
taos> SELECT DISTINCT TBNAME, id, loc FROM st1s1; tbname | id | loc | ================================================== st1s1 | 1 | beijing | Query OK, 1 rows in database (0.001884s)三、删除超级表(DROP STABLE)
DROP STABLE [IF EXISTS] [db_name.]stb_name;删除超级表会级联删除通过该超级表创建的所有子表以及子表中的全部数据。
注意:删除超级表并不会立即释放磁盘空间。TDengine 采用标记删除(soft delete)策略——把该表的数据标记为已删除,查询时这些数据不再出现,但磁盘空间的实际回收延迟到系统自动或用户手动执行数据重整(compaction/重整)时。这一设计与KEEP过期数据的清理时机一致,理解它有助于解释"删除后df空间未立刻下降"的现象。
四、修改超级表(ALTER STABLE)
4.1 完整语法
ALTER STABLE [db_name.]stb_name alter_table_clause alter_table_clause: { alter_table_options | ADD COLUMN col_name column_type | DROP COLUMN col_name | MODIFY COLUMN col_name column_type | ADD TAG tag_name tag_type | DROP TAG tag_name | MODIFY TAG tag_name tag_type | RENAME TAG old_tag_name new_tag_name | ADD BASE ON [db_name.]parent_stb_name [, [db_name.]parent_stb_name] ... | DROP BASE ON [db_name.]parent_stb_name [, [db_name.]parent_stb_name] ... } alter_table_options: alter_table_option ... alter_table_option: { COMMENT 'string_value' | KEEP value }总则:修改超级表结构会对其下所有子表生效,无法针对某个特定子表单独修改表结构。标签结构的修改必须通过超级表下发,TDengine 会自动将该修改作用于该超级表的所有子表。
各子句语义:
| 子句 | 作用与约束 |
|---|---|
ADD COLUMN | 添加数据列,自动作用于所有子表 |
DROP COLUMN | 删除数据列 |
MODIFY COLUMN | 修改数据列宽度;类型必须是可变长类型(BINARY/VARCHAR/NCHAR),列宽只能改大、不能改小 |
ADD TAG | 添加标签;总数不超过128个,单表标签值总长度不超过 16 KB;新增标签在所有子表中的默认值为NULL |
DROP TAG | 删除标签,子表自动同步删除 |
MODIFY TAG | 修改标签列宽度;仅可变长类型可改,且只能改大 |
RENAME TAG | 修改标签名,子表自动同步更新 |
ADD BASE ON/DROP BASE ON | 修改虚拟超级表的继承关系,详见 修改继承关系 |
与普通表一致,超级表的主键列不允许被修改,也不允许通过ADD COLUMN或DROP COLUMN添加或删除主键列。
4.2 各子句的独立用法
增加列
ALTER STABLE stb_name ADD COLUMN col_name column_type;删除列
ALTER STABLE stb_name DROP COLUMN col_name;修改列宽(仅可变长类型,且只能改大)
ALTER STABLE stb_name MODIFY COLUMN col_name data_type(length);添加标签
ALTER STABLE stb_name ADD TAG tag_name tag_type;删除标签
ALTER STABLE stb_name DROP TAG tag_name;修改标签名
ALTER STABLE stb_name RENAME TAG old_tag_name new_tag_name;修改标签列宽度(仅可变长类型,且只能改大)
ALTER STABLE stb_name MODIFY TAG tag_name data_type(length);:::note 除"更新标签值"这一操作针对子表进行外,其余所有标签操作(添加、删除、改名、改宽等)均只能作用于超级表,不能对单个子表执行。对超级表添加标签后,基于该超级表创建的所有子表都会自动增加该标签,且新增标签的默认值为NULL。 :::
4.3 底层实现视角:ALTER STABLE 如何生效
从源码结构看,超级表结构变更在元数据节点(mnode)中通过事务(transaction)机制落地。mndStb.h 声明了关键入口:
int32_t mndAppendAlterStbToTrans(SMnode *pMnode, STrans *pTrans, void *pReqData, int32_t reqDataLen, SStbObj *pAccumBase, SStbObj **ppAccumResult);ALTER STABLE请求被编码为事务中的一条操作追加进事务日志,提交时由mndBuildVCreateStbReq等函数向各个 vnode(数据分片)下发结构变更,从而保证"元数据修改 + 各分片数据文件适配"的原子一致性。同理,创建与删除也有对应的事务封装(mndAddStbToTrans、mndAppendDropStbToTrans),这与上文"删除超级表是标记删除、空间回收依赖数据重整"的行为相吻合:删除操作本身只改元数据,物理空间清理交给后续重整流程。仓库的 mnode 单元测试 stb.cpp 对这套创建/修改/删除流程提供了覆盖,功能级集成测试则位于 test/cases/04-SuperTables/,按01-Create、02-Drop、03-Alter、04-Query四个子目录分别对应本文各章节的语句。
五、超级表查询
使用SELECT语句可以完成在超级表上的投影查询与聚合查询,WHERE子句中既可以按标签筛选,也可以按数据列筛选——这是标签体系在查询侧的直接收益:
-- 按标签维度筛选后聚合 SELECT location, AVG(current) FROM meters WHERE group_id = 'GN_01' GROUP BY location;结果集排序行为需要注意:
- 超级表查询不加
ORDER BY时,返回顺序是"先返回一个子表的全部数据,再返回下一个子表的全部数据",因此整体结果是无序的; - 增加
ORDER BY后,结果会按指定列排序。
如果需要对查询结果做严格的时间序列分析(如连续查询、插值),务必显式写出ORDER BY ts。
六、关键约束速查表
| 约束项 | 普通超级表 | 虚拟超级表 | 源码依据 |
|---|---|---|---|
| 数据列 + 标签总数上限 | 4096 | 数据列最多 32767 | tdef.h |
| 标签数量 | ≤ 128,且 ≥ 1(纯继承除外) | 同左 | tdef.h |
| 单表标签值总长度 | ≤ 16 KB | ≤ 16 KB | tdef.h |
| 单行字节数上限 | 65531 | 524283 | tdef.h |
| 继承父表数 / 引用深度 | — | ≤ 10 父表 / 深度 ≤ 32 | tdef.h |
| 首列 | 必须为TIMESTAMP主键 | 同左 | 文档约束 |
COMPOSITE KEY/ 压缩选项 | 支持 | 不支持 | 文档约束 |
七、小结
- 超级表 DDL 的三大入口是
CREATE STABLE、ALTER STABLE、DROP STABLE,全部语句以超级表为操作对象,结构变更自动级联到所有子表; - 创建时最容易被忽略的是标签约束(≤128 个、总长 ≤16 KB)、
COMPOSITE KEY的类型限制,以及超级表级KEEP与数据库级KEEP的"重整后才生效"语义; - 结构校验与事务落库统一发生在元数据节点,实现集中在 mndStb.c / mndStb.h,各类数值上限定义在 tdef.h,可对照本文第六节速查表逐一核实;
- 查看侧的
SHOW CREATE STABLE与SELECT DISTINCT TBNAME, ...是迁移与标签盘点的高频工具,后两者依赖DISTINCT+TBNAME触发元数据优化路径,写法不可省略。
【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考