TDengine Supertable 完整指南:从 CREATE STABLE 到 ALTER STABLE 的建模、查询与运维
【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine
TDengine 的超级表(Supertable)是一套将**表结构(Schema)与标签(Tags)**分离的数据建模机制:同一类设备/采集点的共性测点定义为列(Metric),设备的静态属性定义为标签(Tag),通过"一个超级表 + 大量子表(Subtable)"的模式承载海量时序设备数据。本文以 Supertables 文档为骨架,结合 TDengine 仓库中的语法解析器(sql.y)、元数据校验实现(mndStb.c)与自动化测试用例,系统讲解超级表的创建、查看、删除、修改与查询,并深入说明复合主键、表级 KEEP、虚拟超级表等进阶能力。读完本文,你将能够独立完成超级表的全生命周期建模、按标签批量管理子表、并通过ALTER STABLE安全演进表结构。
一、超级表是什么:模型与核心概念
在 TDengine 中,一张超级表由以下三部分构成:
- 列(Metric / 数据列):描述采集数据本身的测点,如电压、电流、温度,所有子表共享同一组列定义;
- 时间戳主键:每张表的第一列必须是
TIMESTAMP,系统自动将其设为主键; - 标签(Tag):描述设备的静态维度信息,如设备 ID、地理位置、厂商,用于快速过滤与聚合。
创建超级表后,业务侧通过CREATE TABLE ... USING stb_name TAGS (...)以超级表为模板批量创建子表,每张子表拥有完整列结构 + 一份独立的标签值。数据写入子表,查询既可以按子表进行,也可以在超级表上跨子表做投影与聚合(详见 Tables 中的子表创建语法)。
从仓库源码看,CREATE STABLE与CREATE TABLE在语法层面共用一套列定义解析,但通过一个布尔标记区分:在 sql.y 中,CREATE TABLE ... tags_def_opt走createCreateTableStmt(pCxt, A, false, ...),而CREATE STABLE ... tags_def走createCreateTableStmt(pCxt, A, true, ...)——true即表示创建的是超级表。
二、创建超级表(CREATE STABLE)
2.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} }2.2 一个最小可用示例
CREATE DATABASE power; USE power; CREATE STABLE meters ( ts TIMESTAMP, voltage FLOAT, current FLOAT ) TAGS ( location BINARY(20), group_id INT );以上语句创建一个用于智能电表场景的超级表meters,随后即可批量创建子表:
CREATE TABLE d1001 USING meters TAGS ('California.SanFrancisco', 2); CREATE TABLE d1002 USING meters TAGS ('California.LosAngeles', 2);2.3 命名与基础约束
- 超级表名、列名、标签名的命名规则与普通表一致,详见 Naming Rules:合法字符为英文字母、数字、下划线,必须以字母或下划线开头,大小写不敏感,不能使用保留关键字;如需更自由的命名可用反引号转义。
- 超级表最多 4096 列(含标签列);虚拟超级表最多 32767 个数据列,标签列仍以 128 个为上限。
- 超级表至少包含 3 列:一个时间戳列(主键列)、一个测点列、一个标签列。
- 第一列必须是
TIMESTAMP类型,系统自动将其设为主键。
上述限制在源码中有直接对应。在 tdef.h 中:
#define TSDB_MAX_COLUMNS 32767 // 虚拟表 / 虚拟超级表的最大列数 #define TSDB_MAX_COLUMNS_NON_VIRTUAL 4096 // 普通超级表的最大列数 #define TSDB_MIN_COLUMNS 2 // PRIMARY COLUMN(timestamp) + other columns而 mndStb.c 的 mndCheckCreateStbReq 在创建请求校验时依次检查:numOfColumns + numOfTags不得超过上限、标签数必须 ≥1 且 ≤128、第一列必须是TSDB_DATA_TYPE_TIMESTAMP,任何一项不满足都会返回对应的TSDB_CODE_*错误。这也解释了为什么"至少三列"中的两列下限来自TSDB_MIN_COLUMNS(时间戳 + 1 测点)再加至少 1 个标签。
2.4 COMPOSITE KEY:复合主键
默认情况下,时间戳是唯一主键。通过COMPOSITE KEY关键字,可以为超级表指定第二主键列,与时间戳共同构成复合主键:
CREATE STABLE sensor_data ( ts TIMESTAMP, device_id INT COMPOSITE KEY, value FLOAT ) TAGS (region VARCHAR(16));复合主键列的类型限制:
- 整数类型:
INT、BIGINT、INT UNSIGNED、BIGINT UNSIGNED; - 字符串类型:
VARCHAR、BINARY。
去重语义:当超级表带有复合主键时,只有当时间戳列和第二主键列同时相同,两条记录才被视为重复记录,此时数据库只保留最新的一条;否则两条记录都会保留。
2.5 ENCODE / COMPRESS / LEVEL:列级编码与压缩
ENCODE、COMPRESS、LEVEL三个选项用于在创建列时按列配置一级编码(Encoding)与二级压缩(Compression)算法,完整算法矩阵与默认值见 Data Compression。核心要点:
- 一级压缩(编码):
simple8b、bit-packing、delta-i、delta-d、bss(字节流拆分)、disabled; - 二级压缩:
lz4、zlib、zstd、tsz、xz、disabled; - 压缩级别:
high(压缩率最高、速度最慢)、low(速度最快、压缩率最低)、medium(均衡,默认),支持缩写'h'/'l'/'m'。
示例:
CREATE STABLE telemetry ( ts TIMESTAMP, temp FLOAT ENCODE 'bss' COMPRESS 'zstd' LEVEL 'high', counter BIGINT ENCODE 'delta-i' COMPRESS 'lz4' ) TAGS (node_id INT);注意:虚拟超级表(VIRTUAL 1)不支持ENCODE与COMPRESS。
2.6 TAGS 子句:标签列定义
TAGS子句定义超级表的标签列,有以下限制:
TIMESTAMP类型的标签列在插入时必须提供字面量时间戳值,不支持NOW + 10s这类算术表达式;- 标签列名必须在所有列中唯一,测点列与标签列不能同名;
- 标签列名不能使用保留关键字;
- 超级表最多 128 个标签列,且至少 1 个标签列;
- 所有标签列的总长度不能超过 16 KB。
这些限制同样能在 tdef.h 中找到常量定义:
#define TSDB_MAX_TAGS_LEN 16384 // 16 KB #define TSDB_MAX_TAGS 128并在 mndCheckCreateStbReq 中做了运行时校验。
2.7 表级选项:COMMENT / SMA / KEEP / VIRTUAL
COMMENT:表注释,最大长度 1024 字节,可用于超级表、子表与普通表,详见 Tables。
SMA(Small Materialized Aggregates,小物化聚合):按数据块进行MAX/MIN/SUM的预计算,以加速聚合查询。默认情况下系统会对大多数列自动创建块级 SMA(BINARY、NCHAR等类型不创建);若在创建时显式指定SMA(col_name, ...),则只为列出的列创建块级 SMA:
CREATE STABLE power ( ts TIMESTAMP, voltage FLOAT, current FLOAT, power FLOAT ) TAGS (loc VARCHAR(20)) SMA(voltage, current, power);KEEP(数据保留期):与 Databases 中的库级KEEP语义类似,但存在三点重要差异:
- 超级表级
KEEP必须小于数据库级KEEP; - 超级表级
KEEP不会立即生效——必须先对数据库执行FLUSH再执行COMPACT,被超级表级KEEP标记为过期的数据才会被真正移除; - 如果先 compact 数据库、再修改超级表级
KEEP值、然后又 compact 一次,过期数据可能无法被完全清除。
仓库中的自动化测试 test_stable_keep_compact.py 完整覆盖了这一行为:测试先创建带KEEP的数据库(DURATION {duration}h KEEP {keep}),再通过CREATE STABLE ... KEEP {keep_days}d创建表级 KEEP 的超级表,插入 1~7 天前的历史数据后执行 FLUSH + COMPACT 并验证过期数据是否被清除。测试中对KEEP与DURATION的约束(keep > 3*duration)也印证了数据库创建时必须满足"KEEP 至少为 DURATION 的 3 倍"这一规则。
VIRTUAL(虚拟超级表):VIRTUAL 1表示创建虚拟超级表。虚拟表是逻辑表,本身不存储数据,查询时按虚拟表定义从一张或多张物理表/既有虚拟表中按时间戳对齐读取列数据并即时生成结果集。虚拟超级表作为虚拟子表的模板,有以下限制:
- 不支持
COMPOSITE KEY; - 不支持压缩选项(
ENCODE/COMPRESS); - 可通过
BASE ON子句从一个或多个父虚拟超级表继承列与标签,详见 Virtual Supertable Inheritance。
CREATE STABLE p_device (ts timestamp, status int) TAGS (region int) VIRTUAL 1; CREATE STABLE p_temp (ts timestamp, temp float) TAGS (sensor_id int) BASE ON test_db.p_device VIRTUAL 1;2.8 BASE ON:虚拟超级表继承
BASE ON子句用于虚拟超级表之间的继承,子虚拟超级表(VST)继承父 VST 的所有标签以及除主时间戳外的所有列,自身新增的列与标签追加在继承内容之后。约束包括:
BASE ON要求父子双方都必须是虚拟超级表(VIRTUAL 1);- 父子虚拟超级表必须位于同一个数据库;
- 子表自身的列/标签名不得与任何父表继承来的名称冲突;
- 循环继承会被检测并拒绝;
- 一个 VST 最多继承自10 个父 VST;
- 已有子节点的非叶子 VST 无法直接在其下创建虚拟子表,也不能再作为
BASE ON的目标; - 父 VST 一旦成为非叶子节点,其 Schema 即被冻结:
ADD COLUMN、DROP COLUMN、ADD TAG、DROP TAG、RENAME TAG及标签宽度修改都会被拒绝。
三、查看超级表
3.1 查看全部超级表
SHOW [db_name.]STABLES [LIKE 'pattern'];db_name缺省时显示当前数据库下的超级表,LIKE支持模糊匹配。
3.2 查看超级表创建语句
SHOW CREATE STABLE [db_name.]stb_name;返回该超级表原始的创建 SQL,常用于迁移或克隆已有超级表——在另一个集群中执行该语句即可得到结构完全一致的表。
3.3 查看超级表结构
DESCRIBE [db_name.]stb_name;展示列的字段名、类型与压缩设置。
3.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;table_name既可以是子表(展示该子表标签),也可以是超级表名(此时展示其下所有子表及其标签)。实际输出示例:
taos> SHOW TABLE TAGS FROM st1; tbname | id | loc | ====================================================================== st1s1 | 1 | losangeles | st1s2 | 2 | sanfrancisco | st1s3 | 3 | sacramento | Query OK, 3 rows in database (0.004455s)也可以只查看指定标签列:
taos> SELECT DISTINCT TBNAME, id FROM st1; tbname | id | =============================================== st1s1 | 1 | st1s2 | 2 | st1s3 | 3 | Query OK, 3 rows in database (0.002891s)注意:此语句必须包含DISTINCT与TBNAME,才能保证在数据缺失或数据集很大时结果准确且执行快速。
3.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) | sanfrancisco | Query OK, 2 rows in database (0.003684s)同样支持只查看指定标签:
taos> SELECT DISTINCT TBNAME, id, loc FROM st1s1; tbname | id | loc | ================================================== st1s1 | 1 | sanfrancisco | Query OK, 1 rows in database (0.001884s)从语法层面看,SHOW TABLE TAGS与SHOW TAGS FROM在解析器 sql.y 中是两条独立的文法规则,分别构造QUERY_NODE_SHOW_TAGS_STMT与createShowTableTagsStmt,前者定位单张子表,后者支持通过tag_list_opt指定标签列并在超级表范围聚合输出。
四、删除超级表(DROP STABLE)
DROP STABLE [IF EXISTS] [db_name.]stb_name;:::important 删除超级表会级联删除该超级表下创建的所有子表及其数据,务必谨慎操作。 :::
需要注意的是:删除超级表不会立即释放磁盘空间。超级表会立刻被标记为待删除,查询也不再返回该表的数据,但磁盘空间要等到操作系统自动回收,或用户手动COMPACT数据库后才会释放。这与 Tables 中普通表的删除语义一致。
五、修改超级表(ALTER STABLE)
5.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 }关键语义:修改超级表的 Schema 会影响其下所有子表;任何子表都不能单独修改自身 Schema(仅SET TAG更新标签值除外)。标签定义同样只能在超级表级别修改,并作用于该超级表下的全部子表。
禁止事项:不能对超级表的主键列执行增、删、改操作(不能ADD COLUMN/DROP COLUMN/MODIFY COLUMN主键列)。
各操作说明:
| 操作 | 说明 |
|---|---|
ADD COLUMN | 为超级表增加一个测点列 |
DROP COLUMN | 删除一个测点列,同时从所有子表中删除该列 |
MODIFY COLUMN | 仅可加长BINARY、VARCHAR、NCHAR等变长类型测点列的长度;其他类型不可修改,长度不可缩短 |
ADD TAG | 增加一个标签列(总数 ≤128,总长度 ≤16 KB) |
DROP TAG | 删除一个标签列,同时从所有子表中删除该标签 |
MODIFY TAG | 仅可加长BINARY、VARCHAR、NCHAR等变长类型标签列的长度;其他类型不可修改,长度不可缩短 |
RENAME TAG | 重命名标签列,作用于所有子表 |
ADD BASE ON/DROP BASE ON | 修改虚拟超级表的继承关系,详见 Alter Inheritance |
在解析器 sql.y 中可以看到:ALTER STABLE alter_table_clause与ALTER TABLE共用同一套alter_table_clause文法,仅通过setAlterSuperTableType标记为超级表操作;ADD BASE ON/DROP BASE ON则对应createAlterTableBaseOn,这是超级表(确切说是虚拟超级表)独有的修改能力。
5.2 增加测点列
ALTER STABLE stb_name ADD COLUMN col_name column_type;5.3 删除测点列
ALTER STABLE stb_name DROP COLUMN col_name;5.4 修改测点列长度
ALTER STABLE stb_name MODIFY COLUMN col_name data_type(length);- 目标列必须是
BINARY、VARCHAR或NCHAR等变长类型; - 新长度必须大于现有长度,不允许缩短。
5.5 增加标签列
ALTER STABLE stb_name ADD TAG tag_name tag_type;注意:增加后标签总数不能超过 128,所有标签总长度不能超过 16 KB。当向超级表新增标签列时,其下所有子表会自动继承新标签,新标签的默认值为NULL。
5.6 删除标签列
ALTER STABLE stb_name DROP TAG tag_name;5.7 重命名标签列
ALTER STABLE stb_name RENAME TAG old_tag_name new_tag_name;5.8 修改标签列长度
ALTER STABLE stb_name MODIFY TAG tag_name data_type(length);- 目标标签必须是
BINARY、VARCHAR或NCHAR等变长类型; - 新长度必须大于现有长度,不允许缩短。
仓库测试 test_stable_alter_basic.py 覆盖了上述列/标签增删改的基础路径,可作为自行验证时的参照。
六、查询超级表
超级表支持使用SELECT进行投影与聚合查询,并可在WHERE子句中同时对测点列与标签列进行过滤。例如:
SELECT COUNT(*), AVG(voltage) FROM meters WHERE group_id = 2 AND ts >= NOW - 1h;结果排序说明:如果超级表查询不包含ORDER BY,返回结果会按子表分组——先返回某个子表的全部记录,再返回下一个子表的全部记录,即返回数据整体不保证有序。如需严格排序,必须显式添加ORDER BY:
SELECT * FROM meters WHERE ts >= NOW - 1h ORDER BY ts;:::note 除"更新标签值"外,所有标签操作都只能在超级表上进行,不能对某个子表单独增加、删除或修改标签列。 :::
七、实战建议与注意事项
- 建模先行:把随设备变化的测点放列(Column),把相对静态的维度放标签(Tag),标签数尽量控制在 128 以内、总长度 16 KB 以内;超级表总列数(含标签)不要超过 4096。
- 利用复合主键:当同一时间戳下同一设备可能出现多条不同来源记录时,用
COMPOSITE KEY声明第二主键,获得"时间戳 + 来源"维度的去重语义。 - 按需压缩:整数/浮点列可组合
ENCODE与COMPRESS降低存储成本;BINARY/NCHAR默认二级压缩为zstd,无需额外配置即可获得较好压缩率。 - KEEP 的生效时机:表级
KEEP不会即时生效,必须FLUSH+COMPACT后才清除过期数据,且反复 compact + 改 KEEP 可能导致过期数据残留,生产环境应避免频繁调整。 - Schema 演进而非重建:需要新增测点/标签时优先使用
ALTER STABLE ADD COLUMN / ADD TAG,一次性作用于全部子表;删除列/标签前确认该操作会级联到所有子表。 - 迁移复用:用
SHOW CREATE STABLE导出的建表语句可直接在目标集群重放,保证结构完全一致。
八、总结
超级表是 TDengine 面向工业物联网(IIoT)场景的核心建模设施。本文以 Supertables 为主线,完整覆盖了CREATE STABLE(含复合主键、标签约束、SMA、KEEP、VIRTUAL、BASE ON)、SHOW/DESCRIBE系列查看命令、DROP STABLE的级联语义与空间释放机制、ALTER STABLE的列/标签/继承关系全量修改能力,以及超级表查询的排序行为。每一处关键限制都能在仓库源码中找到对应实现:列数上限定义在 tdef.h,标签上限定义在 tdef.h,创建校验逻辑位于 mndStb.c 的 mndCheckCreateStbReq,语法规则位于 sql.y。结合仓库中的测试用例(test_stable_keep_compact.py、test_stable_alter_basic.py),读者可以在本地环境直接复现并验证上述全部行为。
【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考