Timescale Cloud:性能、扩展、企业级
自托管产品
MST
压缩时序数据可将数据块大小减少 90% 以上。这可以节省存储成本,并使查询以极快的速度运行。
启用压缩后,超表中的数据会逐个数据块地进行压缩。当数据块被压缩时,多个记录会组合成一行。该行的列包含一个类似数组的结构,用于存储所有数据。这意味着它将相同的数据存储在单个行中,而不是使用多行来存储数据。因为单行占用的磁盘空间比多行少,所以可以减少所需的磁盘空间量,并且还可以加快查询速度。
例如,如果您的表数据看起来像这样
时间戳 | 设备 ID | 设备类型 | CPU | 磁盘 IO |
---|---|---|---|---|
12:00:01 | A | SSD | 70.11 | 13.4 |
12:00:01 | B | HDD | 69.70 | 20.5 |
12:00:02 | A | SSD | 70.12 | 13.2 |
12:00:02 | B | HDD | 69.69 | 23.4 |
12:00:03 | A | SSD | 70.14 | 13.0 |
12:00:03 | B | HDD | 69.70 | 25.2 |
您可以将其转换为数组形式的单行,如下所示
时间戳 | 设备 ID | 设备类型 | CPU | 磁盘 IO |
---|---|---|---|---|
[12:00:01, 12:00:01, 12:00:02, 12:00:02, 12:00:03, 12:00:03] | [A, B, A, B, A, B] | [SSD, HDD, SSD, HDD, SSD, HDD] | [70.11, 69.70, 70.12, 69.69, 70.14, 69.70] | [13.4, 20.5, 13.2, 23.4, 13.0, 25.2] |
本节解释了如何启用原生压缩,然后详细介绍了最重要的压缩设置,以帮助您获得最佳的压缩比。
每个表都有不同的模式,但它们确实有一些需要您考虑的共同点。
考虑具有以下属性的 `metrics` 表
列 | 类型 | 排序规则 | 可空 | 默认值 |
---|---|---|---|---|
time | 带有时区的时间戳 | 非空 | ||
device_id | 整数 | 非空 | ||
device_type | 整数 | 非空 | ||
cpu | 双精度 | |||
disk_io | 双精度 |
所有超表都有一个主要维度,用于将表分区成数据块。主要维度在创建超表时给定。在下面的示例中,您可以看到一个经典的以 `time` 列作为主要维度的时序用例。此外,还有 `cpu` 和 `disk_io` 两列包含随时间捕获的值,以及一个 `device_id` 列用于捕获这些值的设备。列可以通过几种不同的方式使用
- 您可以使用列中的值作为查找键,在上面的示例中,`device_id` 就是此类列的典型示例。
- 您可以使用列进行表分区。这通常是一个时间列,例如上面示例中的 `time`,但也可以使用其他类型进行表分区。
- 您可以使用列作为筛选器来缩小选择数据的范围。`device_type` 列就是一个例子,您可以决定只查看固态硬盘 (SSD) 等。其余列通常是您正在收集的值或指标。这些通常以其他方式进行聚合或呈现。`cpu` 和 `disk_io` 列是此类列的典型示例。
SELECT avg(cpu), sum(disk_io)FROM metricsWHERE device_type = ‘SSD’AND time >= now() - ‘1 day’::interval;
当超表中的数据块被压缩时,其中存储的数据会重新组织并以列序而不是行序存储。因此,不可能使用相同未压缩的数据块模式版本,必须创建一个不同的模式。这由 TimescaleDB 自动处理,但这有一些影响:压缩比和查询性能非常依赖于压缩数据的顺序和结构,因此在设置压缩时需要考虑一些因素。超表上的索引不能总是以相同的方式用于压缩数据。
注意
在超表上设置的索引仅用于包含未压缩数据的数据块。Timescale 在压缩期间创建并使用自定义索引来合并 `segmentby` 和 `orderby` 参数,这些参数在读取压缩数据时使用。更多内容将在下一节中介绍。
基于之前的模式,数据筛选应在特定时间段内进行,并且分析以设备粒度完成。这种数据访问模式有利于组织适合压缩的数据布局。
对数据进行排序将极大地影响压缩比和查询性能。在一个维度上变化的行应该彼此靠近。由于我们主要处理时序数据,时间维度是一个很好的选择。大多数情况下,数据以可预测的方式变化,遵循某种趋势。我们可以利用这一事实对数据进行编码,使其存储空间更小。例如,如果您按时间对记录进行排序,它们将按该顺序进行压缩,随后也将按相同顺序访问。
在我们的示例表上使用以下配置设置
ALTER TABLE metricsSET (timescaledb.compress, timescaledb.compress_orderby='time');
将生成以下数据布局。
时间戳 | 设备 ID | 设备类型 | CPU |
---|---|---|---|
[12:00:01, 12:00:01, 12:00:02, 12:00:02, 12:00:03, 12:00:03] | [A, B, A, B, A, B] | [SSD, HDD, SSD, HDD, SSD, HDD] | [70.11, 69.70, 70.12, 69.69, 70.14, 69.70] |
`time` 列用于数据排序,这使得使用 `time` 列进行筛选效率更高。
postgres=# select avg(cpu) from metrics where time >= '2024-03-01 00:00:00+01' and time < '2024-03-02 00:00:00+01';avg--------------------0.4996848437842719(1 row)Time: 87,218 mspostgres=# ALTER TABLE metricsSET (timescaledb.compress,timescaledb.compress_segmentby = 'device_id',timescaledb.compress_orderby='time');ALTER TABLETime: 6,607 mspostgres=# SELECT compress_chunk(c) FROM show_chunks('metrics') c;compress_chunk----------------------------------------_timescaledb_internal._hyper_2_4_chunk_timescaledb_internal._hyper_2_5_chunk_timescaledb_internal._hyper_2_6_chunk(3 rows)Time: 3070,626 ms (00:03,071)postgres=# select avg(cpu) from metrics where time >= '2024-03-01 00:00:00+01' and time < '2024-03-02 00:00:00+01';avg------------------0.49968484378427(1 row)Time: 45,384 ms
这使得时间列成为数据排序的完美选择,因为测量值会随着时间的推移而演变。如果您只使用它作为唯一的压缩设置,您很可能会获得足够好的压缩比以节省大量存储空间。然而,有效访问数据取决于您的用例和查询。在这种设置下,您将始终需要使用时间维度访问数据,然后根据任何其他条件筛选所有行。
压缩数据的分段应基于您访问数据的方式。基本上,您希望以一种方式分段数据,以便您的查询可以更容易地在正确的时间获取正确的数据。也就是说,您的查询应该决定如何分段数据,以便它们可以被优化并产生更好的查询性能。
例如,如果您想使用特定的 `device_id` 值访问单个设备(无论是所有记录还是特定时间范围内的记录),您将需要在行访问时逐个筛选所有这些记录。为了解决这个问题,您可以使用 `device_id` 列进行分段。如果您正在查找特定的设备 ID,这将使您在压缩数据上运行分析查询的速度快得多。
考虑以下查询
SELECT device_id, AVG(cpu) AS avg_cpu, AVG(disk_io) AS avg_disk_ioFROM metricsWHERE device_id = 5GROUP BY device_id;
如您所见,该查询通过将其所有值组合在一起来基于 `device_id` 标识符进行大量工作。我们可以利用这一事实,通过设置压缩来围绕此列中的值对数据进行分段,从而加快这些类型的查询。
在我们的示例表上使用以下配置设置
ALTER TABLE metricsSET (timescaledb.compress,timescaledb.compress_segmentby='device_id',timescaledb.compress_orderby='time');
将生成以下数据布局。
time | device_id | device_type | cpu | disk_io | energy_consumption |
---|---|---|---|---|---|
[12:00:02, 12:00:01] | 1 | [SSD,SSD] | [88.2, 88.6] | [20, 25] | [0.8, 0.85] |
[12:00:02, 12:00:01] | 2 | [HDD,HDD] | [300.5, 299.1] | [30, 40] | [0.9, 0.95] |
... | ... | ... | ... | ... | ... |
分段列 `device_id` 用于根据该列的值将数据点分组在一起。这使得访问特定设备更加高效。
postgres=# \timingTiming is on.postgres=# SELECT device_id, AVG(cpu) AS avg_cpu, AVG(disk_io) AS avg_disk_ioFROM metricsWHERE device_id = 5GROUP BY device_id;device_id | avg_cpu | avg_disk_io-----------+--------------------+---------------------5 | 0.4972598866221261 | 0.49820356730280524(1 row)Time: 177,399 mspostgres=# ALTER TABLE metricsSET (timescaledb.compress,timescaledb.compress_segmentby = 'device_id',timescaledb.compress_orderby='time');ALTER TABLETime: 6,607 mspostgres=# SELECT compress_chunk(c) FROM show_chunks('metrics') c;compress_chunk----------------------------------------_timescaledb_internal._hyper_2_4_chunk_timescaledb_internal._hyper_2_5_chunk_timescaledb_internal._hyper_2_6_chunk(3 rows)Time: 3070,626 ms (00:03,071)postgres=# SELECT device_id, AVG(cpu) AS avg_cpu, AVG(disk_io) AS avg_disk_ioFROM metricsWHERE device_id = 5GROUP BY device_id;device_id | avg_cpu | avg_disk_io-----------+-------------------+---------------------5 | 0.497259886622126 | 0.49820356730280535(1 row)Time: 42,139 ms
注意
在单个批次中一起压缩的行数(如我们上面看到的)为 1000。如果您的数据块没有足够的数据来创建足够大的批次,您的压缩比将降低。在定义压缩设置时需要考虑到这一点。
关键词
在此页面上发现问题?报告问题" width="16" height="16" class="inline m-0 ml-1"> in GitHub。