TDengine Tag 索引 — 子表筛选的核心机制

TDengine Tag 索引 — 子表筛选的核心机制

分类:9.索引 |篇章:01 Tag 索引

适用版本:TDengine v3.x(v3.3.x / v3.4.x) | 最后更新:2026-07-10

Tag 索引是 TDengine 跨子表查询的核心。"过亿子表 Tag 等值过滤毫秒响应"靠的就是 Tag 索引。本文讲解 Tag 索引的结构、使用方式、设计原则。

核心概念速查表

概念说明
Tag超级表的标签列
Tag IndexTag 列上的索引
B-Tree IndexTag 索引常用结构
Index Coverage索引覆盖(无需回表)
Tag CardinalityTag 列的基数
CREATE INDEX显式创建 Tag 索引

详细解析

1. Tag 与子表的关系

回顾: 超级表 meters (TAGS: location, groupid) 子表创建: CREATE TABLE d001 USING meters TAGS('Beijing', 1); CREATE TABLE d002 USING meters TAGS('Beijing', 2); CREATE TABLE d003 USING meters TAGS('Shanghai', 1); Tag 存储: - 每个子表存一份 Tag 值 - 同时存在 MNode 的元数据中(用于路由) Tag 索引的作用: WHERE location='Beijing' 时 → 不需要遍历所有子表 → 用索引快速找到 Beijing 的子表列表

2. 默认 Tag 索引

建超级表时: 第一个 Tag 列默认建索引 CREATE STABLE meters (...) TAGS (location VARCHAR(32), groupid INT); → location 自动有索引 → groupid 默认无索引 显式索引: CREATE INDEX idx_groupid ON meters (groupid); 索引类型: - B-Tree(默认) - 适合等值和范围查询

3. Tag 索引的使用

查询自动使用 Tag 索引: SELECT * FROM meters WHERE location='Beijing' AND ts > now-1h; 执行流程: ① 用 location 索引找到所有 Beijing 的子表 ② 对每个子表做时间裁剪扫描 ③ 汇总结果 → 不需要扫描非 Beijing 的子表 支持的查询模式: ✓ WHERE tag = 'value' ✓ WHERE tag IN ('v1', 'v2') ✓ WHERE tag LIKE 'prefix%' (前缀匹配) ✓ WHERE tag1 = 'v1' AND tag2 = 'v2' (多列) ✓ WHERE tag BETWEEN x AND y

4. 索引覆盖

当 SELECT 只涉及 Tag 列: SELECT DISTINCT location FROM meters; → 仅扫描索引,无需读数据 SELECT location, groupid, COUNT(DISTINCT tbname) FROM meters GROUP BY location, groupid; → Tag 聚合,仅索引扫描 性能特点: - 不读 .data 文件 - 仅查询 META(元数据) - 毫秒返回(即使千万子表)

5. Tag 索引的存储

存储位置: - MNode 维护全局 Tag 索引 - 各 VNode 维护本地 Tag 索引 数据结构: - B+Tree - Key: (super_table_id, tag_value) - Value: 子表 ID 列表 更新时机: - 创建子表:插入索引 - DROP TABLE:删除索引项 - ALTER TAG:更新索引 查询路由: ① 客户端 Catalog 查询: 用 location='Beijing' 查 MNode 索引 得到匹配子表列表 + 对应 VGroup ② 客户端按 VGroup 分发查询 ③ 各 VNode 处理本地子表

6. Tag 设计原则

高效 Tag 设计: ① 高频过滤维度做 Tag: - 地域、设备类型、用户ID(中等基数) - 状态、分类、标签 ② 高基数 Tag 慎用: - 用户ID 1 亿 → 子表 1 亿,元数据爆炸 - 改用 Tag 值组合(如部门+用户) ③ Tag 数量适中: - 通常 < 20 个 - 过多 Tag 增加元数据开销 ④ Tag 值长度适中: - 短字符串高效 - 长 JSON Tag 慎用 反例: Tag (device_id) = 设备唯一 ID → 每个设备一个子表 → 1 亿设备 = 1 亿子表 → 元数据查询慢 改进: Tag (factory, line) = (工厂, 产线) → 子表数 = 工厂数 × 产线数 → 设备号作为普通列

7. 多 Tag 索引

-- 多列各自建索引CREATEINDEXidx_locONmeters(location);CREATEINDEXidx_grpONmeters(groupid);-- 查询能用多个索引SELECT*FROMmetersWHERElocation='Beijing'ANDgroupid=1;-- → 引擎选择性最高的索引或多索引交集-- 查看索引SHOWINDEXESFROMmeters;-- 删除索引DROPINDEXidx_grp;

8. Tag 索引限制

限制: ① 不支持组合索引(多列单一索引) - 只能各列分别索引 ② 不支持函数索引: - CREATE INDEX ON (UPPER(tag)) 不支持 ③ JSON Tag 索引有限: - 顶层 Tag 索引 OK - JSON 内部字段索引视版本 ④ 字符串 Tag 长度限制 最佳实践: - 第一个 Tag 是最常用的过滤维度 - 其他需要过滤的 Tag 显式建索引 - 不要把 Tag 当作通用属性存储

代码示例

索引设计示例

-- 电力监控场景CREATESTABLE meters(tsTIMESTAMP,currentFLOAT,voltageINT)TAGS(locationVARCHAR(32),-- 高频过滤 → 默认索引line_idVARCHAR(32),-- 中频过滤device_modelVARCHAR(64)-- 偶尔过滤);-- 增加 line_id 索引(高频)CREATEINDEXidx_lineONmeters(line_id);-- device_model 不建索引(偶尔用)-- 验证索引SHOWINDEXESFROMmeters;

高效查询

-- ✓ 利用第一 Tag 索引SELECT*FROMmetersWHERElocation='Beijing'ANDts>now-1h;-- ✓ 利用 line_id 索引SELECT*FROMmetersWHEREline_id='LINE_A'ANDts>now-1h;-- ✓ 多 Tag 组合SELECT*FROMmetersWHERElocation='Beijing'ANDline_id='LINE_A'ANDts>now-1h;-- ✓ Tag 聚合(仅索引扫描)SELECTlocation,COUNT(DISTINCTtbname)FROMmetersGROUPBYlocation;

低效模式

-- ✗ 无 Tag 索引列 + 大范围SELECT*FROMmetersWHEREdevice_model='M1'ANDts>now-1y;-- 改进:device_model 建索引CREATEINDEXidx_modelONmeters(device_model);

性能考量

Tag 索引性能

场景性能
第一 Tag 等值微秒级
多 Tag AND毫秒级
Tag IN 列表毫秒级(按列表大小线性)
Tag 范围与子表数成正比
无 Tag 过滤(全扫)秒~分钟

子表数与查询性能

子表数Tag 等值查询延迟
1000< 1ms
10万< 10ms
100万< 100ms
1000万< 1s

FAQ

Q1: Tag 索引能加速哪些查询?

凡是 WHERE 含 Tag 等值/IN/范围/前缀模糊的查询都受益。Tag 聚合(仅 Tag 列)只读索引最快。

Q2: 不建索引能否过滤 Tag?

可以,但变为线性扫描所有子表元数据。子表多时慢。

Q3: 修改 Tag 值会影响索引吗?

会自动更新。ALTER TABLE d001 SET TAG location='Shanghai'会更新索引。

Q4: 索引占用多少存储?

每个子表的 Tag 值 + 几十字节索引开销。100 万子表约几十 MB。

Q5: JSON Tag 怎么索引?

CREATESTABLE m(...)TAGS(info JSON);-- 通常用 info.field 访问,索引能力视版本-- 复杂 JSON 查询不如普通 Tag 高效

参考

系统构架篇

  • 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 分布式查询执行》
  • 12-《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 内部实现》

关于 TDengine

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