时序数据可能是独特的,因为它需要处理浅查询和宽查询,例如“过去 10 分钟内部署发生了什么”,以及深查询和窄查询,例如“过去 24 小时内此服务器的平均 CPU 使用率是多少”。时序数据通常也具有非常高的插入速率;每秒数十万次的写入对于时序数据集来说非常正常。此外,时序数据通常非常精细,并且数据以比许多其他数据集更高的分辨率收集。这可能会导致随着时间的推移收集 TB 级的数据。
所有这些都意味着,如果您需要出色的压缩率,您可能需要在开始摄取数据之前考虑数据库的设计。本节介绍在设计数据库以获得最大压缩效果时需要考虑的一些事项。
TimescaleDB 构建于 PostgreSQL 之上,PostgreSQL 本质上是一个面向行的数据库。由于时序数据是按时间顺序访问的,因此当您启用压缩时,TimescaleDB 会将许多宽数据行转换为单行数据,称为数组形式。这意味着新的宽行的每个字段都存储一个包含整个列的有序数据集。
例如,如果您有一个包含如下数据的表
时间戳 | 设备 ID | 状态代码 | 温度 |
---|---|---|---|
12:00:01 | A | 0 | 70.11 |
12:00:01 | B | 0 | 69.70 |
12:00:02 | A | 0 | 70.12 |
12:00:02 | B | 0 | 69.69 |
12:00:03 | A | 0 | 70.14 |
12:00:03 | B | 4 | 69.70 |
您可以将其转换为数组形式的单行,如下所示
时间戳 | 设备 ID | 状态代码 | 温度 |
---|---|---|---|
[12:00:01, 12:00:01, 12:00:02, 12:00:02, 12:00:03, 12:00:03] | [A, B, A, B, A, B] | [0, 0, 0, 0, 0, 4] | [70.11, 69.70, 70.12, 69.69, 70.14, 69.70] |
即使在压缩任何数据之前,这种格式也可以通过减少每行开销来立即节省存储空间。PostgreSQL 通常每行添加少量字节的开销。因此,即使没有任何压缩,此示例中的模式在磁盘上也比以前的格式更小。
这种格式排列数据,使相似的数据(例如时间戳、设备 ID 或温度读数)连续存储。这意味着您可以随后使用特定于类型的压缩算法来进一步压缩数据,并且每个数组都是单独压缩的。有关所用压缩方法的更多信息,请参阅压缩方法部分。
当数据为数组格式时,您可以非常快速地执行需要列子集的查询。例如,如果您有一个像这样的查询,它要求过去一天的平均温度
SELECT time_bucket(‘1 minute’, timestamp) as minuteAVG(temperature)FROM tableWHERE timestamp > now() - interval ‘1 day’ORDER BY minute DESCGROUP BY minute;
查询引擎可以仅获取和解压缩时间戳和温度列,以有效地计算并返回这些结果。
最后,TimescaleDB 使用非内联磁盘页来存储压缩数组。这意味着行内数据指向存储压缩数组的辅助磁盘页,并且主表中的实际行变得非常小,因为它现在只是指向数据的指针。当查询像这样存储的数据时,仅从磁盘读取所需列的压缩数组,从而通过减少磁盘读取和写入来进一步提高性能。
在前面的示例中,数据库无法知道需要获取和解压缩哪些行才能解析查询。例如,数据库无法轻易确定哪些行包含过去一天的数据,因为时间戳本身位于压缩列中。您不希望必须解压缩数据块甚至整个 hypertable 中的所有数据,才能确定需要哪些行。
TimescaleDB 自动在行中包含更多信息,并包含额外的分组以提高查询性能。当您手动或通过压缩策略压缩 hypertable 时,指定 ORDER BY
列会有所帮助。
ORDER BY
列指定压缩批次中的行如何排序。对于大多数时序工作负载,这是按时间戳排序的,因此如果您未指定 ORDER BY
列,TimescaleDB 默认使用时间列。您还可以指定其他维度,例如位置。
对于每个 ORDER BY
列,TimescaleDB 自动创建额外的列,用于存储该列的最小值和最大值。这样,查询计划器可以查看压缩列中时间戳的范围,而无需进行任何解压缩,并确定该行是否可能与查询匹配。
当您压缩 hypertable 时,您还可以选择指定 SEGMENT BY
列。这允许您按特定列对压缩行进行分段,以便每个压缩行对应于有关单个项目的数据,例如,特定的设备 ID。这进一步允许查询计划器确定该行是否可能与查询匹配,而无需首先解压缩列。例如
设备 ID | 时间戳 | 状态代码 | 温度 | 最小时间戳 | 最大时间戳 |
---|---|---|---|---|---|
A | [12:00:01, 12:00:02, 12:00:03] | [0, 0, 0] | [70.11, 70.12, 70.14] | 12:00:01 | 12:00:03 |
B | [12:00:01, 12:00:02, 12:00:03] | [0, 0, 4] | [69.70, 69.69, 69.70] | 12:00:01 | 12:00:03 |
通过这种方式分段数据,对设备 A 在时间间隔之间的查询变得非常快。查询计划器可以使用索引来查找设备 A 的那些行,这些行包含至少一些与指定间隔对应的时间戳,即使是顺序扫描也相当快,因为评估设备 ID 或时间戳不需要解压缩。这意味着查询执行器仅解压缩与那些选定行对应的时间戳和温度列。
关键词
在此页面上发现问题?报告问题 或 在 GitHub 上编辑此页面。