TDengine 索引使用指南 — 何时建、怎么建、怎么用

分类:9.索引 |篇章:03 索引使用指南

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

索引设计是数据库性能的根基。本文整合 TDengine 多类索引(Tag 索引、SMA、TSMA、RSMA)的使用决策树,给出"看到查询模式立刻知道该建什么索引"的实用指导。

核心概念速查表

索引自动/手动加速对象
块 SMA自动块级过滤/聚合
文件 SMA自动文件级裁剪
第一 Tag 索引自动子表筛选
额外 Tag 索引手动多 Tag 筛选
TSMA手动长期范围聚合
RSMA数据库级分层存储

详细解析

1. 索引决策树

查询模式 → 推荐索引: ① WHERE ts > T → 块/文件 SMA(自动) ② WHERE tag = 'v' → Tag 索引 - 第一 Tag:默认有 - 其他 Tag:手动 CREATE INDEX ③ WHERE current > 100 → 块 SMA(自动) ④ AVG/SUM/MAX/MIN 简单聚合 → 块 SMA + TSMA ⑤ 大时间范围聚合(月/年)→ TSMA / RSMA ⑥ 子表筛选高基数 Tag → 重新设计 Schema(Tag 改为列) ⑦ 复杂表达式聚合 → 流计算

2. 实战 1:电力监控

-- 场景:1 亿设备数据,常用查询模式:-- A. 单设备最近 1 小时数据-- B. 某城市所有设备聚合-- C. 全网日报小时聚合-- 表设计(Tag 决定子表数)CREATESTABLE meters(tsTIMESTAMP,currentFLOAT,voltageINT)TAGS(cityVARCHAR(32),-- 200 个城市(低基数)districtVARCHAR(64),-- 几万区县factory_idVARCHAR(32)-- 几十万工厂);-- 子表数 = 工厂数 × 设备/厂 ≈ 1 亿-- A 查询: WHERE tbname='d001' AND ts > now-1h-- → 自动用块 SMA 时间裁剪-- → 单子表查询,无需 Tag 索引-- B 查询: WHERE city='Beijing' AND ts > now-1h-- → 第一 Tag 索引(city)-- → 自动用块 SMA-- C 查询: SELECT _wstart, AVG(current) FROM meters-- WHERE ts > now-1y INTERVAL(1h)-- → 创建 TSMA 加速CREATETSMA meters_1hONmetersFUNCTION(AVG(current),MAX(current),MIN(current))INTERVAL(1h);

3. 实战 2:IoT 网关数据

-- 场景:100 万传感器,500 种类型-- 常用查询:-- A. 单传感器历史-- B. 某类型传感器统计-- C. 异常事件检测CREATESTABLE sensors(tsTIMESTAMP,valueFLOAT,statusTINYINT)TAGS(sensor_typeVARCHAR(32),-- 500 种(高频过滤)factory_idVARCHAR(32),-- 100 个工厂zone_idVARCHAR(32)-- 几千个区域);-- 默认 sensor_type 索引(第一 Tag)-- factory_id 是常用过滤 → 显式建索引CREATEINDEXidx_factoryONsensors(factory_id);-- 异常事件流(实时)CREATESTREAM s_anomalyINTOanomaly_logASSELECT_wstart,tbname,MAX(value)FROMsensorsWHEREstatus>1PARTITIONBYtbnameINTERVAL(1m);

4. 实战 3:金融行情

-- 场景:5000 只股票,秒级行情-- 查询:-- A. 单股票日 K-- B. 板块/行业聚合-- C. 全市场指数CREATESTABLE quotes(tsTIMESTAMP,priceFLOAT,volumeBIGINT,...)TAGS(symbolVARCHAR(16),-- 5000 个股票代码(一对一子表)sectorVARCHAR(32),-- 30 个行业exchangeVARCHAR(16)-- 几个交易所);-- 默认 symbol 索引-- sector 是常用聚合维度CREATEINDEXidx_sectorONquotes(sector);-- 日 K 用 TSMACREATETSMA quotes_1dONquotesFUNCTION(FIRST(price)ASopen,MAX(price)AShigh,MIN(price)ASlow,LAST(price)ASclose,SUM(volume)ASvolume)INTERVAL(1d);-- 历史归档用 RSMA(建库时)CREATEDATABASEquotes_db RETENTIONS'1s:7d,1m:90d,1h:5y';

5. 反模式与改进

反模式 1: 高基数 Tag CREATE STABLE orders (...) TAGS (user_id BIGINT); -- 1 亿用户 = 1 亿子表 = 元数据爆炸 改进: CREATE STABLE orders (...) TAGS (region VARCHAR(32), shard INT); -- user_id 作为普通列 -- shard = user_id % 1000 控制子表数 反模式 2: 全字段 Tag CREATE STABLE t (...) TAGS (a, b, c, d, e, f, g, h); -- 过多 Tag 增加元数据 改进: 保留 3~5 个常用过滤 Tag,其他作普通列 反模式 3: 长字符串 Tag TAGS (description VARCHAR(1024)) -- Tag 值过大,索引膨胀 改进: Tag 仅存类别/ID,详情存普通列 反模式 4: 复杂查询不命中索引 SELECT * FROM meters WHERE UPPER(location) = 'BEIJING'; -- 函数包裹 → Tag 索引失效 改进: SELECT * FROM meters WHERE location = 'beijing'; -- 或建表时统一大小写

6. 索引维护操作

-- 查看索引SHOWINDEXESFROMmeters;SHOWTSMAS;-- 创建索引CREATEINDEXidx_nameONmeters(column);CREATETSMA tsma_nameONmetersFUNCTION(...)INTERVAL(...);-- 删除索引DROPINDEXidx_name;DROPTSMA tsma_name;-- 修改不支持,需 DROP 再 CREATE

7. 索引性能验证

验证流程: ① 准备测试数据 ② EXPLAIN 看计划 ③ EXPLAIN ANALYZE 看实际 ④ 验证关键指标: - blocks_skipped 高 → SMA 生效 - 子表 scan 数量小 → Tag 索引生效 - rows_examined 小 → 索引覆盖好 ⑤ 基准测试对比延迟

8. 索引升级策略

随业务变化调整: ① 监控慢查询日志 ② 识别高频查询模式 ③ 评估是否缺索引 ④ 在业务低峰创建索引(建索引本身耗时) ⑤ 验证查询加速效果 ⑥ 持续观察 何时考虑重构: - 子表数失控(亿级以上) - Tag 设计不合理 - 查询模式发生根本变化 重构方案: - 新建表迁移数据 - 或重新 ALTER TABLE 修改 Tag(视支持情况)

代码示例

综合应用:智慧城市

-- 数据库:分层存储CREATEDATABASEcity_dbPRECISION'ms'KEEP1825RETENTIONS'1s:30d,1m:1y,1h:5y';USEcity_db;-- 超级表CREATESTABLE devices(tsTIMESTAMP,valueFLOAT,statusTINYINT)TAGS(districtVARCHAR(32),-- 区device_typeVARCHAR(32),-- 类型vendorVARCHAR(32)-- 厂商)ROLLUP(AVG,MAX,MIN);-- → 自动 RSMA-- 显式索引CREATEINDEXidx_dtypeONdevices(device_type);CREATEINDEXidx_vendorONdevices(vendor);-- TSMA 加速 5 分钟报表CREATETSMA devices_5mONdevicesFUNCTION(AVG(value),COUNT(*))INTERVAL(5m);-- 流计算异常检测CREATESTREAM s_alarmINTOalarm_logASSELECT_wstart,tbname,MAX(value)FROMdevicesWHEREstatus>1PARTITIONBYtbnameINTERVAL(10s);

性能考量

不同索引的成本与收益

索引创建成本维护成本查询收益
默认 Tag 索引0极低
额外 Tag 索引
块 SMA00
TSMA中(回填)极高
RSMA极高
流计算(替代)极高

索引设计原则

原则说明
第一 Tag 最重要默认有索引,放最常用过滤列
额外索引按需不要预先加所有索引
TSMA 针对慢查询仅为已知慢查询模式建
避免高基数 Tag优先考虑普通列

FAQ

Q1: 索引创建慢怎么办?

大表新建索引耗时长。建议低峰期执行;可考虑表/数据库重建。

Q2: 索引和数据存储分离吗?

Tag 索引在 MNode/VNode 元数据中。SMA 在 .data 文件 Header。TSMA 单独文件。

Q3: 每个查询都需要索引吗?

不需要。简单时间范围查询有自动 SMA 即可。仅在 EXPLAIN 表明扫描过多时才加索引。

Q4: 索引数量上限?

无明确硬上限,但过多索引:

  • 增加写入开销
  • 元数据膨胀
  • 查询优化器选择慢

建议每表 < 5 个手动索引。

Q5: 怎么知道一个查询用了哪个索引?

EXPLAIN VERBOSE 显示选择的索引和扫描方式。

参考

系统构架篇

  • 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 内部实现》

索引

  • 01-《TDengine Tag 索引》
  • 02-《TDengine SMA 索引》