TDengine SMA 索引 — 块级/文件级统计索引

分类 :9.索引 | 篇章 :02 SMA 索引


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

SMA(Small Materialized Aggregation)是 TDengine 在数据块/文件级别自动维护的统计索引。它不像传统 B-Tree 索引,而是为聚合查询和过滤剪枝服务。本文聚焦"SMA 作为索引"的视角。

核心概念速查表

概念 说明
Block SMA 数据块统计(min/max/sum/count)
File SMA 数据文件统计
Skipping Index 跳过索引(基于范围)
Bloom Filter 布隆过滤(视版本)
Index Effectiveness 索引有效性

详细解析

1. SMA 索引的定位

复制代码
传统索引(B-Tree)vs SMA 索引:

  B-Tree 索引(Tag 索引):
    - 行级精确定位
    - 适合等值/范围查询
    - 占空间大
    
  SMA 索引:
    - 块级统计跳过
    - 适合聚合 + 大范围过滤
    - 占空间极小(< 1%)
    - 时序数据场景优势明显


定位:
  - Tag 索引:跨子表筛选
  - SMA 索引:单子表内的块剪枝

2. Block SMA 工作原理

复制代码
每个数据块 4096 行,存储元数据:

  Block Header {
    time_range: [ts_min, ts_max],
    row_count: 4096,
    cols: [
      { name: "current", min: 20.5, max: 25.8, sum: 95000, count: 4096 },
      { name: "voltage", min: 218, max: 223, sum: 902160, count: 4096 },
      { name: "phase", min: 0.45, max: 0.55, sum: 2048, count: 4096 },
    ]
  }


查询时的判断:
  SELECT * FROM d001 WHERE current > 100 AND ts > T1;
  
  对每个块:
    if block.time_range.max < T1: 跳过
    if block.cols.current.max < 100: 跳过
    else: 进入块读取

3. SMA 用于聚合优化

复制代码
SELECT AVG(current) FROM d001 WHERE ts > T1;

执行:
  ① 找到符合时间范围的所有块
  ② 对每个块:
     - 直接读取 SMA 中的 sum 和 count
     - 不解码原始数据
  ③ 累加:total_sum / total_count


效果:
  - 100 万行数据:扫描 ~250 个块
  - 仅读块 Header(~50KB)
  - 不读 .data 主体(数 GB)
  - 毫秒返回


支持函数:
  ✓ COUNT, SUM, AVG(需 sum/count)
  ✓ MIN, MAX
  ✓ FIRST, LAST(部分场景)
  ✗ PERCENTILE, MEDIAN(需扫行)

4. SMA 用于过滤剪枝

复制代码
WHERE 子句的剪枝:

  WHERE current > 100
  
  对每个块:
    if block.cols.current.max <= 100: 整块跳过
    if block.cols.current.min > 100: 整块满足,可能加速
    else: 块部分匹配,需扫描行


示例:
  100 万行分 250 个块
  WHERE current > 100:
    - 200 块 max < 100 → 跳过
    - 30 块 min > 100 → 全选
    - 20 块部分匹配 → 扫描行
    
  实际扫描行数:20 × 4096 = 82K(节省 92%)

5. 时间维度的 SMA

复制代码
时间列是隐式 SMA 关键:

  每块的 time_range 用于时间裁剪:
    WHERE ts > T → 跳过所有 ts_max < T 的块
    WHERE ts BETWEEN T1 AND T2 → 跳过范围外
  
  时间裁剪是最有效的剪枝(时序数据按时间分布)


三级裁剪:
  ① 文件级:跳过整个 .data 文件
  ② 块级:跳过文件内部分块
  ③ 行级:块内进一步过滤(按数据列)

6. SMA 索引效果监控

sql 复制代码
-- EXPLAIN ANALYZE 看实际效果
EXPLAIN ANALYZE 
SELECT AVG(current) FROM meters 
WHERE ts > now-1h AND voltage > 200;

-- 关键指标:
--   blocks_total: 总块数
--   blocks_scanned: 实际扫描的块数
--   blocks_skipped: 跳过的块数(SMA 生效)
--   rows_examined: 实际读取行数
--   rows_returned: 返回行数


-- 比率 = blocks_skipped / blocks_total
-- 高比率说明 SMA 有效

7. 影响 SMA 索引效果的因素

复制代码
影响因素:

  ① 块大小(MAXROWS):
     - 小块:更细粒度剪枝,但块多
     - 大块:单块容纳更多数据,剪枝粒度粗
     - 默认 4096 通常合适
     
  ② 数据分布:
     - 同块内数据相似 → 剪枝效果好
     - 同块内数据差异大 → 剪枝难
     
  ③ 列类型:
     - 数值类型剪枝有效
     - 字符串类型 SMA 较弱
     
  ④ 数据排序:
     - 按 ts 自然排序 → 时间剪枝最优
     - 数据列乱序 → 数据列剪枝弱

8. SMA 索引设计建议

复制代码
最佳实践:

  ① 让常查询列与时间有相关性:
     - 时间相近的数据值也相近 → 块内 min/max 紧凑
     - 利于过滤剪枝
     
  ② 控制块大小:
     - 默认 MAXROWS 4096 适合大多数场景
     - 极少行/极多行可能需调整
     
  ③ 不要过度依赖 SMA:
     - 复杂表达式无法用 SMA
     - 字符串 LIKE 等无 SMA
     
  ④ 配合 Tag 索引:
     - Tag 索引筛选子表
     - SMA 索引剪枝块
     - 两者协同最强

代码示例

SMA 效果验证

sql 复制代码
-- 准备数据
INSERT INTO d001 USING meters TAGS('Beijing', 1) 
VALUES (NOW-1d, 25, 220, 0.5);
-- ... 写入百万行

-- 测试 1: 时间范围(SMA 最有效)
EXPLAIN ANALYZE 
SELECT COUNT(*) FROM d001 WHERE ts > now-1h;
-- 期望 blocks_skipped 大

-- 测试 2: 数据列过滤
EXPLAIN ANALYZE 
SELECT COUNT(*) FROM d001 WHERE current > 100;
-- 期望部分 blocks_skipped(取决于数据分布)

-- 测试 3: 聚合(SMA 直接命中)
EXPLAIN ANALYZE 
SELECT AVG(current) FROM d001 WHERE ts > now-1d;
-- 期望 rows_examined 几乎为 0(直接用 SMA sum/count)

提升 SMA 命中

sql 复制代码
-- ✗ 复杂过滤无法用 SMA
SELECT * FROM meters WHERE current > AVG(current);

-- ✓ 简单常量比较
SELECT * FROM meters WHERE current > 100;

-- ✗ 函数包裹
SELECT * FROM meters WHERE ABS(phase - 0.5) < 0.1;

-- ✓ 直接范围
SELECT * FROM meters WHERE phase BETWEEN 0.4 AND 0.6;

性能考量

SMA 索引性能特点

场景 SMA 效果
时间裁剪 极高(90%+ 跳过)
数值列过滤 中~高(取决于分布)
聚合 SUM/AVG/COUNT 极高(直接读 SMA)
MIN/MAX 极高(直接读 SMA)
字符串过滤
复杂表达式 无效

存储开销

占比
块 SMA < 1%
文件 SMA < 0.1%
TSMA/RSMA 1%~10%
Tag 索引 < 0.1%

FAQ

Q1: SMA 索引可以手动创建吗?

块/文件 SMA 自动维护。TSMA/RSMA 需要 CREATE TSMA 或建库 RETENTIONS。

Q2: SMA 索引会失效吗?

写入新数据 → 新块自动有 SMA。Compaction 重算 SMA。极端故障 + 数据修复后 SMA 自动重建。

Q3: 字符串列 SMA 弱怎么办?

  • 转为枚举(Tag)
  • 用前缀提取列
  • 或接受较低性能

Q4: 如何判断 SMA 是否生效?

EXPLAIN ANALYZE 看 blocks_skipped。比率 > 80% 说明有效。

Q5: 不同版本 SMA 行为差异?

总体方向一致。新版本可能增加 Bloom Filter、字符串 min/max 等。具体看版本 Release Note。

参考

系统构架篇

数据模型

存储引擎

查询引擎

数据写入

数据订阅

预聚合

索引

关于 TDengine

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

相关推荐
kisshyshy几秒前
从0到1彻底理解流式输出:先读懂Vue的“乐高积木”,再拧开LLM的“数据水龙头”
javascript·vue.js·人工智能
ting94520006 分钟前
纯技术硬核解析:Timbal AI 全栈底层架构、引擎原理与生产级 AI 应用落地实现
人工智能·架构
用户6919026813396 分钟前
Agent 开发 主流 skills推荐
人工智能
意图共鸣8 分钟前
意图共鸣科技7月13日发布《智能体三角模型白皮书》|商用AI智能体的通用构造范式深度解读
人工智能·科技
dora11 分钟前
使用 Cling 实现 DLNA 投屏:从局域网发现到媒体播放控制
android·android things·tvos
触底反弹11 分钟前
Vue 实战:手把手教你实现 ChatGPT 同款打字机效果
前端·javascript·人工智能
秦先生在广东13 分钟前
Hallmark:一个拒绝“AI味“的设计技能工具深度解析
人工智能
老金带你玩AI13 分钟前
Codex109天重置23次,明天还要再送一次
人工智能
kylin-运维13 分钟前
k8s可视化看板嵌入AI助手(悬浮对话球)
人工智能·容器·kubernetes·aicoding
code_pgf18 分钟前
LLM/MLLM 与世界模型在具身智能中的角色、局限与分类
人工智能