时序数据库数据切分查询技术:PARTITION BY与SLIMIT深度解析

尔悦

2026-04-17 /

在处理大规模时序数据时,数据切分查询是一种重要的技术手段。TDengine时序数据库提供了PARTITION BY子句,支持按维度对数据进行切分,然后在每个切分空间内进行独立计算。本文将详细介绍数据切分查询的原理和应用。

一、数据切分查询概述

1.1 什么是数据切分查询

数据切分查询是指将数据按照一定维度进行分组,每个分组形成一个独立的数据空间,然后在这些空间内分别执行后续的计算操作。

1.2 数据切分的价值

  • 并行计算:不同分片可以并行处理,提高查询效率
  • 逻辑清晰:将复杂查询分解为多个独立计算单元
  • 结果可控:可以限制返回的分片数量,控制结果规模

二、PARTITION BY子句

2.1 语法结构

PARTITION BY part_list

part_list可以是任意的标量表达式,包括:

  • 列名
  • 常量
  • 标量函数
  • 它们的组合

2.2 处理流程

TDengine按如下方式处理数据切分子句:

  1. 数据切分子句位于WHERE子句之后
  2. 数据切分子句将表数据按指定的维度进行切分,每个切分的分片进行指定的计算
  3. 计算由之后的子句定义(窗口子句、GROUP BY子句或SELECT子句)
  4. 数据切分子句可以和窗口切分子句(或GROUP BY子句)一起使用,此时后面的子句作用在每个切分的分片上

2.3 基本示例

按标签切分数据:

SELECT location, avg(voltage) 
FROM meters 
PARTITION BY location;

查询结果:

 location                  | avg(voltage)        |
======================================================
 California.SantaClara     | 243.962050000000005 |
 California.SanFrancisco   | 243.962050000000005 |
 California.SanJose        | 243.962050000000005 |
 California.LosAngles      | 243.962050000000005 |
 California.SanDiego       | 243.962050000000005 |
 California.Sunnyvale      | 243.962050000000005 |
 California.PaloAlto       | 243.962050000000005 |
 California.Cupertino      | 243.962050000000005 |
 California.MountainView   | 243.962050000000005 |
 California.Campbell       | 243.962050000000005 |
Query OK, 10 row(s) in set (2.415961s)

三、PARTITION BY与窗口查询结合

3.1 组合使用场景

当需要对每个设备分别进行时间窗口聚合时,可以将PARTITION BY与窗口子句结合使用。

3.2 完整示例

SELECT tbname, _wstart, _wend, avg(voltage) 
FROM meters 
WHERE ts >= "2022-01-01T00:00:00+08:00" 
AND ts < "2022-01-01T00:05:00+08:00" 
PARTITION BY tbname 
INTERVAL(1m, 5s) 
SLIMIT 2;

这条SQL的执行流程:

  1. WHERE过滤:筛选指定时间范围的数据
  2. PARTITION BY切分:按子表名(tbname)切分数据
  3. INTERVAL窗口:在每个分片内按1分钟窗口聚合
  4. SLIMIT限制:只返回前2个分片的结果

查询结果:

 tbname | _wstart               | _wend                 | avg(voltage)        |
======================================================================================
 d2     | 2021-12-31 23:59:05.000 | 2022-01-01 00:00:05.000 | 253.000000000000000 |
 d2     | 2022-01-01 00:00:05.000 | 2022-01-01 00:01:05.000 | 244.166666666666657 |
 d2     | 2022-01-01 00:01:05.000 | 2022-01-01 00:02:05.000 | 241.833333333333343 |
 d2     | 2022-01-01 00:02:05.000 | 2022-01-01 00:03:05.000 | 243.166666666666657 |
 d2     | 2022-01-01 00:03:05.000 | 2022-01-01 00:04:05.000 | 240.833333333333343 |
 d2     | 2022-01-01 00:04:05.000 | 2022-01-01 00:05:05.000 | 244.800000000000011 |
 d26    | 2021-12-31 23:59:05.000 | 2022-01-01 00:00:05.000 | 253.000000000000000 |
 d26    | 2022-01-01 00:00:05.000 | 2022-01-01 00:01:05.000 | 244.166666666666657 |
 d26    | 2022-01-01 00:01:05.000 | 2022-01-01 00:02:05.000 | 241.833333333333343 |
 d26    | 2022-01-01 00:02:05.000 | 2022-01-01 00:03:05.000 | 243.166666666666657 |
 d26    | 2022-01-01 00:03:05.000 | 2022-01-01 00:04:05.000 | 240.833333333333343 |
 d26    | 2022-01-01 00:04:05.000 | 2022-01-01 00:05:05.000 | 244.800000000000011 |
Query OK, 12 row(s) in set (0.021265s)

四、SLIMIT与SOFFSET

4.1 SLIMIT子句

SLIMIT用于限制返回的分片数量:

-- 只返回前1个分片
SELECT tbname, avg(voltage)
FROM meters
PARTITION BY tbname
SLIMIT 1;

4.2 SOFFSET子句

SOFFSET用于指定跳过的分片数量:

-- 跳过前5个分片,返回接下来的3个分片
SELECT tbname, avg(voltage)
FROM meters
PARTITION BY tbname
SLIMIT 3 SOFFSET 5;

4.3 分页查询

结合SLIMIT和SOFFSET实现分片分页:

-- 第一页
SELECT tbname, avg(voltage)
FROM meters
PARTITION BY tbname
SLIMIT 10 SOFFSET 0;

-- 第二页
SELECT tbname, avg(voltage)
FROM meters
PARTITION BY tbname
SLIMIT 10 SOFFSET 10;

五、常用切分维度

5.1 按子表名切分

最常用的切分方式,按设备分片:

SELECT tbname, COUNT(*), AVG(voltage)
FROM meters
WHERE ts >= '2022-01-01 00:00:00'
PARTITION BY tbname;

5.2 按标签切分

按标签值进行分组:

SELECT location, COUNT(*), AVG(voltage)
FROM meters
WHERE ts >= '2022-01-01 00:00:00'
PARTITION BY location;

5.3 按表达式切分

支持使用表达式作为切分依据:

-- 按分组ID模3切分
SELECT group_id % 3 as grp, AVG(voltage)
FROM meters
PARTITION BY group_id % 3;

六、PARTITION BY与GROUP BY的区别

特性PARTITION BYGROUP BY
作用位置WHERE之后窗口子句之后
与窗口子句可以一起使用不能一起使用
计算方式每个分片独立计算全局聚合
结果形式多个分片的结果集单一聚合结果

6.1 GROUP BY示例

SELECT groupid, avg(voltage) 
FROM meters 
WHERE ts >= "2022-01-01T00:00:00+08:00" 
GROUP BY groupid;

6.2 PARTITION BY示例

SELECT tbname, avg(voltage) 
FROM meters 
WHERE ts >= "2022-01-01T00:00:00+08:00" 
PARTITION BY tbname;

七、高级应用场景

7.1 设备级时间窗口分析

对每个设备分别进行时间窗口聚合:

SELECT tbname, _wstart, avg(voltage), max(voltage), min(voltage)
FROM meters
WHERE ts >= '2022-01-01 00:00:00' AND ts < '2022-01-02 00:00:00'
PARTITION BY tbname
INTERVAL(1h)
SLIMIT 10;

7.2 地区分组统计

按地区分组进行统计:

SELECT location, 
       COUNT(*) as device_count,
       AVG(voltage) as avg_voltage,
       MAX(voltage) as max_voltage
FROM meters
PARTITION BY location;

7.3 多维度切分

支持多表达式切分:

SELECT location, group_id, AVG(voltage)
FROM meters
PARTITION BY location, group_id;

八、性能优化建议

8.1 合理选择切分维度

  • 选择区分度高的列作为切分维度
  • 避免切分后分片数量过多
  • 标签列是理想的切分维度

8.2 使用SLIMIT控制结果

  • 大规模数据查询时使用SLIMIT限制分片数量
  • 结合SOFFSET实现分页
  • 避免一次性返回过多数据

8.3 配合时间范围过滤

  • 在WHERE子句中指定时间范围
  • 减少每个分片的数据量
  • 提高查询效率

九、注意事项

9.1 子句顺序

正确的子句顺序:

SELECT ...
FROM ...
WHERE ...
PARTITION BY ...
[窗口子句]
[SLIMIT ...]

9.2 与GROUP BY的限制

  • PARTITION BY不能与GROUP BY同时使用
  • 根据需求选择合适的分组方式

9.3 结果排序

PARTITION BY不保证结果顺序,如需排序应使用ORDER BY:

SELECT tbname, avg(voltage)
FROM meters
PARTITION BY tbname
ORDER BY tbname;

总结

数据切分查询是TDengine时序数据库的重要特性,通过PARTITION BY子句,开发者可以灵活地按维度对数据进行切分,实现并行计算和精细化分析。结合窗口子句和SLIMIT限制,可以构建强大的时序数据分析查询。这种技术特别适用于物联网和工业场景,能够高效处理海量设备数据,为工业数据管理平台(IDMP)和实时数据库应用提供灵活的数据分析能力。TDengine凭借其完善的数据切分查询功能,成为大规模时序数据分析的理想选择。